text: # System library imports
  from IPython.external.qt import QtGui
  
  # Local imports
  from IPython.utils.py3compat import unicode_type
  from IPython.utils.traitlets import Bool
  from .console_widget import ConsoleWidget
  
  
  class HistoryConsoleWidget(ConsoleWidget):
      """ A ConsoleWidget that keeps a history of the commands that have been
          executed and provides a readline-esque interface to this history.
      """
  
      #------ Configuration ------------------------------------------------------
  
      # If enabled, the input buffer will become "locked" to history movement when
      # an edit is made to a multi-line input buffer. To override the lock, use
      # Shift in conjunction with the standard history cycling keys.
      history_lock = Bool(False, config=True)
  
      #---------------------------------------------------------------------------
      # 'object' interface
      #---------------------------------------------------------------------------
  
      def __init__(self, *args, **kw):
          super(HistoryConsoleWidget, self).__init__(*args, **kw)
  
          # HistoryConsoleWidget protected variables.
          self._history = []
          self._history_edits = {}
          self._history_index = 0
          self._history_prefix = ''
  
      #---------------------------------------------------------------------------
      # 'ConsoleWidget' public interface
      #---------------------------------------------------------------------------
  
      def execute(self, source=None, hidden=False, interactive=False):
          """ Reimplemented to the store history.
          """
          if not hidden:
              history = self.input_buffer if source is None else source
  
          executed = super(HistoryConsoleWidget, self).execute(
              source, hidden, interactive)
  
          if executed and not hidden:
              # Save the command unless it was an empty string or was identical
              # to the previous command.
              history = history.rstrip()
              if history and (not self._history or self._history[-1] != history):
                  self._history.append(history)
  
              # Emulate readline: reset all history edits.
              self._history_edits = {}
  
              # Move the history index to the most recent item.
              self._history_index = len(self._history)
  
          return executed
  
      #---------------------------------------------------------------------------
      # 'ConsoleWidget' abstract interface
      #---------------------------------------------------------------------------
  
      def _up_pressed(self, shift_modifier):
          """ Called when the up key is pressed. Returns whether to continue
              processing the event.
          """
          prompt_cursor = self._get_prompt_cursor()
          if self._get_cursor().blockNumber() == prompt_cursor.blockNumber():
              # Bail out if we're locked.
              if self._history_locked() and not shift_modifier:
                  return False
  
              # Set a search prefix based on the cursor position.
              col = self._get_input_buffer_cursor_column()
              input_buffer = self.input_buffer
              # use the *shortest* of the cursor column and the history prefix
              # to determine if the prefix has changed
              n = min(col, len(self._history_prefix))
              
              # prefix changed, restart search from the beginning
              if (self._history_prefix[:n] != input_buffer[:n]):
                  self._history_index = len(self._history)
              
              # the only time we shouldn't set the history prefix
              # to the line up to the cursor is if we are already
              # in a simple scroll (no prefix),
              # and the cursor is at the end of the first line
              
              # check if we are at the end of the first line
              c = self._get_cursor()
              current_pos = c.position()
              c.movePosition(QtGui.QTextCursor.EndOfLine)
              at_eol = (c.position() == current_pos)
              
              if self._history_index == len(self._history) or \
                  not (self._history_prefix == '' and at_eol) or \
                  not (self._get_edited_history(self._history_index)[:col] == input_buffer[:col]):
                  self._history_prefix = input_buffer[:col]
  
              # Perform the search.
              self.history_previous(self._history_prefix,
                                      as_prefix=not shift_modifier)
  
              # Go to the first line of the prompt for seemless history scrolling.
              # Emulate readline: keep the cursor position fixed for a prefix
              # search.
              cursor = self._get_prompt_cursor()
              if self._history_prefix:
                  cursor.movePosition(QtGui.QTextCursor.Right,
                                      n=len(self._history_prefix))
              else:
                  cursor.movePosition(QtGui.QTextCursor.EndOfLine)
              self._set_cursor(cursor)
  
              return False
  
          return True
  
      def _down_pressed(self, shift_modifier):
          """ Called when the down key is pressed. Returns whether to continue
              processing the event.
          """
          end_cursor = self._get_end_cursor()
          if self._get_cursor().blockNumber() == end_cursor.blockNumber():
              # Bail out if we're locked.
              if self._history_locked() and not shift_modifier:
                  return False
  
              # Perform the search.
              replaced = self.history_next(self._history_prefix,
                                              as_prefix=not shift_modifier)
  
              # Emulate readline: keep the cursor position fixed for a prefix
              # search. (We don't need to move the cursor to the end of the buffer
              # in the other case because this happens automatically when the
              # input buffer is set.)
              if self._history_prefix and replaced:
                  cursor = self._get_prompt_cursor()
                  cursor.movePosition(QtGui.QTextCursor.Right,
                                      n=len(self._history_prefix))
                  self._set_cursor(cursor)
  
              return False
  
          return True
  
      #---------------------------------------------------------------------------
      # 'HistoryConsoleWidget' public interface
      #---------------------------------------------------------------------------
  
      def history_previous(self, substring='', as_prefix=True):
          """ If possible, set the input buffer to a previous history item.
  
          Parameters
          ----------
          substring : str, optional
              If specified, search for an item with this substring.
          as_prefix : bool, optional
              If True, the substring must match at the beginning (default).
  
          Returns
          -------
          Whether the input buffer was changed.
          """
          index = self._history_index
          replace = False
          while index > 0:
              index -= 1
              history = self._get_edited_history(index)
              if (as_prefix and history.startswith(substring)) \
                  or (not as_prefix and substring in history):
                  replace = True
                  break
  
          if replace:
              self._store_edits()
              self._history_index = index
              self.input_buffer = history
  
          return replace
  
      def history_next(self, substring='', as_prefix=True):
          """ If possible, set the input buffer to a subsequent history item.
  
          Parameters
          ----------
          substring : str, optional
              If specified, search for an item with this substring.
          as_prefix : bool, optional
              If True, the substring must match at the beginning (default).
  
          Returns
          -------
          Whether the input buffer was changed.
          """
          index = self._history_index
          replace = False
          while index < len(self._history):
              index += 1
              history = self._get_edited_history(index)
              if (as_prefix and history.startswith(substring)) \
                  or (not as_prefix and substring in history):
                  replace = True
                  break
  
          if replace:
              self._store_edits()
              self._history_index = index
              self.input_buffer = history
  
          return replace
  
      def history_tail(self, n=10):
          """ Get the local history list.
  
          Parameters
          ----------
          n : int
              The (maximum) number of history items to get.
          """
          return self._history[-n:]
  
      def _request_update_session_history_length(self):
          msg_id = self.kernel_client.shell_channel.execute('',
              silent=True,
              user_expressions={
                  'hlen':'len(get_ipython().history_manager.input_hist_raw)',
                  }
              )
          self._request_info['execute'][msg_id] = self._ExecutionRequest(msg_id, 'save_magic')
  
      def _handle_execute_reply(self, msg):
          """ Handles replies for code execution, here only session history length
          """
          msg_id = msg['parent_header']['msg_id']
          info = self._request_info['execute'].pop(msg_id,None)
          if info and info.kind == 'save_magic' and not self._hidden:
              content = msg['content']
              status = content['status']
              if status == 'ok':
                  self._max_session_history = int(
                      content['user_expressions']['hlen']['data']['text/plain']
                  )
  
      def save_magic(self):
          # update the session history length
          self._request_update_session_history_length()
  
          file_name,extFilter = QtGui.QFileDialog.getSaveFileName(self,
              "Enter A filename",
              filter='Python File (*.py);; All files (*.*)'
              )
  
          # let's the user search/type for a file name, while the history length
          # is fetched
  
          if file_name:
              hist_range, ok = QtGui.QInputDialog.getText(self,
                  'Please enter an interval of command to save',
                  'Saving commands:',
                  text=str('1-'+str(self._max_session_history))
                  )
              if ok:
                  self.execute("%save"+" "+file_name+" "+str(hist_range))
  
      #---------------------------------------------------------------------------
      # 'HistoryConsoleWidget' protected interface
      #---------------------------------------------------------------------------
  
      def _history_locked(self):
          """ Returns whether history movement is locked.
          """
          return (self.history_lock and
                  (self._get_edited_history(self._history_index) !=
                   self.input_buffer) and
                  (self._get_prompt_cursor().blockNumber() !=
                   self._get_end_cursor().blockNumber()))
  
      def _get_edited_history(self, index):
          """ Retrieves a history item, possibly with temporary edits.
          """
          if index in self._history_edits:
              return self._history_edits[index]
          elif index == len(self._history):
              return unicode_type()
          return self._history[index]
  
      def _set_history(self, history):
          """ Replace the current history with a sequence of history items.
          """
          self._history = list(history)
          self._history_edits = {}
          self._history_index = len(self._history)
  
      def _store_edits(self):
          """ If there are edits to the current input buffer, store them.
          """
          current = self.input_buffer
          if self._history_index == len(self._history) or \
                  self._history[self._history_index] != current:
              self._history_edits[self._history_index] = current
  