summaryrefslogtreecommitdiff
path: root/cmd2
diff options
context:
space:
mode:
authorkotfu <kotfu@kotfu.net>2019-02-09 13:43:41 -0700
committerkotfu <kotfu@kotfu.net>2019-02-09 13:43:41 -0700
commit321a8c72a48d227011177bb91006ed20607a1e44 (patch)
treec69b95e823cb897d45ee04e3eb8b02f123181122 /cmd2
parent80327e0a7f21424554ade6626be0798ce6392a1d (diff)
downloadcmd2-git-321a8c72a48d227011177bb91006ed20607a1e44.tar.gz
Extract history classes and test into their own files
Diffstat (limited to 'cmd2')
-rw-r--r--cmd2/cmd2.py141
-rw-r--r--cmd2/history.py151
2 files changed, 152 insertions, 140 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index ba2b6e8a..69a6c2aa 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -50,6 +50,7 @@ from . import utils
from .argparse_completer import AutoCompleter, ACArgumentParser, ACTION_ARG_CHOICES
from .clipboard import can_clip, get_paste_buffer, write_to_paste_buffer
from .parsing import StatementParser, Statement, Macro, MacroArg
+from .history import History, HistoryItem
# Set up readline
from .rl_utils import rl_type, RlType, rl_get_point, rl_set_prompt, vt100_support, rl_make_safe_prompt
@@ -287,39 +288,6 @@ class EmptyStatement(Exception):
pass
-class HistoryItem(str):
- """Class used to represent an item in the History list"""
- listformat = ' {:>4} {}\n'
- ex_listformat = ' Ex: {}\n'
-
- def __new__(cls, statement: Statement):
- """Create a new instance of HistoryItem
-
- We must override __new__ because we are subclassing `str` which is
- immutable and takes a different number of arguments as Statement.
- """
- hi = super().__new__(cls, statement.raw)
- hi.statement = statement
- hi.idx = None
- return hi
-
- @property
- def expanded(self) -> str:
- """Return the command as run which includes shortcuts and aliases resolved plus any changes made in hooks"""
- return self.statement.expanded_command_line
-
- def pr(self, verbose: bool) -> str:
- """Represent a HistoryItem in a pretty fashion suitable for printing.
-
- :return: pretty print string version of a HistoryItem
- """
- ret_str = self.listformat.format(self.idx, str(self).rstrip())
- if verbose and self != self.expanded:
- ret_str += self.ex_listformat.format(self.expanded.rstrip())
-
- return ret_str
-
-
class Cmd(cmd.Cmd):
"""An easy but powerful framework for writing line-oriented command interpreters.
@@ -3810,113 +3778,6 @@ class Cmd(cmd.Cmd):
self._cmdfinalization_hooks.append(func)
-class History(list):
- """ A list of HistoryItems that knows how to respond to user requests. """
-
- # noinspection PyMethodMayBeStatic
- def _zero_based_index(self, onebased: int) -> int:
- """Convert a one-based index to a zero-based index."""
- result = onebased
- if result > 0:
- result -= 1
- return result
-
- def _to_index(self, raw: str) -> Optional[int]:
- if raw:
- result = self._zero_based_index(int(raw))
- else:
- result = None
- return result
-
- spanpattern = re.compile(r'^\s*(?P<start>-?\d+)?\s*(?P<separator>:|(\.{2,}))?\s*(?P<end>-?\d+)?\s*$')
-
- def span(self, raw: str) -> List[HistoryItem]:
- """Parses the input string search for a span pattern and if if found, returns a slice from the History list.
-
- :param raw: string potentially containing a span of the forms a..b, a:b, a:, ..b
- :return: slice from the History list
- """
- if raw.lower() in ('*', '-', 'all'):
- raw = ':'
- results = self.spanpattern.search(raw)
- if not results:
- raise IndexError
- if not results.group('separator'):
- return [self[self._to_index(results.group('start'))]]
- start = self._to_index(results.group('start')) or 0 # Ensure start is not None
- end = self._to_index(results.group('end'))
- reverse = False
- if end is not None:
- if end < start:
- (start, end) = (end, start)
- reverse = True
- end += 1
- result = self[start:end]
- if reverse:
- result.reverse()
- return result
-
- rangePattern = re.compile(r'^\s*(?P<start>[\d]+)?\s*-\s*(?P<end>[\d]+)?\s*$')
-
- def append(self, new: Statement) -> None:
- """Append a HistoryItem to end of the History list
-
- :param new: command line to convert to HistoryItem and add to the end of the History list
- """
- new = HistoryItem(new)
- list.append(self, new)
- new.idx = len(self)
-
- def get(self, getme: Optional[Union[int, str]]=None) -> List[HistoryItem]:
- """Get an item or items from the History list using 1-based indexing.
-
- :param getme: optional item(s) to get (either an integer index or string to search for)
- :return: list of HistoryItems matching the retrieval criteria
- """
- if not getme:
- return self
- try:
- getme = int(getme)
- if getme < 0:
- return self[:(-1 * getme)]
- else:
- return [self[getme - 1]]
- except IndexError:
- return []
- except ValueError:
- range_result = self.rangePattern.search(getme)
- if range_result:
- start = range_result.group('start') or None
- end = range_result.group('start') or None
- if start:
- start = int(start) - 1
- if end:
- end = int(end)
- return self[start:end]
-
- getme = getme.strip()
-
- if getme.startswith(r'/') and getme.endswith(r'/'):
- finder = re.compile(getme[1:-1], re.DOTALL | re.MULTILINE | re.IGNORECASE)
-
- def isin(hi):
- """Listcomp filter function for doing a regular expression search of History.
-
- :param hi: HistoryItem
- :return: bool - True if search matches
- """
- return finder.search(hi)
- else:
- def isin(hi):
- """Listcomp filter function for doing a case-insensitive string search of History.
-
- :param hi: HistoryItem
- :return: bool - True if search matches
- """
- return utils.norm_fold(getme) in utils.norm_fold(hi)
- return [itm for itm in self if isin(itm)]
-
-
class Statekeeper(object):
"""Class used to save and restore state during load and py commands as well as when redirecting output or pipes."""
def __init__(self, obj: Any, attribs: Iterable) -> None:
diff --git a/cmd2/history.py b/cmd2/history.py
new file mode 100644
index 00000000..0989b7db
--- /dev/null
+++ b/cmd2/history.py
@@ -0,0 +1,151 @@
+# coding=utf-8
+"""
+History management classes
+"""
+
+import re
+
+from typing import List, Optional, Union
+
+from . import utils
+from .parsing import Statement
+
+
+class HistoryItem(str):
+ """Class used to represent one command in the History list"""
+ listformat = ' {:>4} {}\n'
+ ex_listformat = ' Ex: {}\n'
+
+ def __new__(cls, statement: Statement):
+ """Create a new instance of HistoryItem
+
+ We must override __new__ because we are subclassing `str` which is
+ immutable and takes a different number of arguments as Statement.
+ """
+ hi = super().__new__(cls, statement.raw)
+ hi.statement = statement
+ hi.idx = None
+ return hi
+
+ @property
+ def expanded(self) -> str:
+ """Return the command as run which includes shortcuts and aliases resolved plus any changes made in hooks"""
+ return self.statement.expanded_command_line
+
+ def pr(self, verbose: bool) -> str:
+ """Represent a HistoryItem in a pretty fashion suitable for printing.
+
+ :return: pretty print string version of a HistoryItem
+ """
+ ret_str = self.listformat.format(self.idx, str(self).rstrip())
+ if verbose and self != self.expanded:
+ ret_str += self.ex_listformat.format(self.expanded.rstrip())
+
+ return ret_str
+
+
+class History(list):
+ """ A list of HistoryItems that knows how to respond to user requests. """
+
+ # noinspection PyMethodMayBeStatic
+ def _zero_based_index(self, onebased: int) -> int:
+ """Convert a one-based index to a zero-based index."""
+ result = onebased
+ if result > 0:
+ result -= 1
+ return result
+
+ def _to_index(self, raw: str) -> Optional[int]:
+ if raw:
+ result = self._zero_based_index(int(raw))
+ else:
+ result = None
+ return result
+
+ spanpattern = re.compile(r'^\s*(?P<start>-?\d+)?\s*(?P<separator>:|(\.{2,}))?\s*(?P<end>-?\d+)?\s*$')
+
+ def span(self, raw: str) -> List[HistoryItem]:
+ """Parses the input string search for a span pattern and if if found, returns a slice from the History list.
+
+ :param raw: string potentially containing a span of the forms a..b, a:b, a:, ..b
+ :return: slice from the History list
+ """
+ if raw.lower() in ('*', '-', 'all'):
+ raw = ':'
+ results = self.spanpattern.search(raw)
+ if not results:
+ raise IndexError
+ if not results.group('separator'):
+ return [self[self._to_index(results.group('start'))]]
+ start = self._to_index(results.group('start')) or 0 # Ensure start is not None
+ end = self._to_index(results.group('end'))
+ reverse = False
+ if end is not None:
+ if end < start:
+ (start, end) = (end, start)
+ reverse = True
+ end += 1
+ result = self[start:end]
+ if reverse:
+ result.reverse()
+ return result
+
+ rangePattern = re.compile(r'^\s*(?P<start>[\d]+)?\s*-\s*(?P<end>[\d]+)?\s*$')
+
+ def append(self, new: Statement) -> None:
+ """Append a HistoryItem to end of the History list
+
+ :param new: command line to convert to HistoryItem and add to the end of the History list
+ """
+ new = HistoryItem(new)
+ list.append(self, new)
+ new.idx = len(self)
+
+ def get(self, getme: Optional[Union[int, str]]=None) -> List[HistoryItem]:
+ """Get an item or items from the History list using 1-based indexing.
+
+ :param getme: optional item(s) to get (either an integer index or string to search for)
+ :return: list of HistoryItems matching the retrieval criteria
+ """
+ if not getme:
+ return self
+ try:
+ getme = int(getme)
+ if getme < 0:
+ return self[:(-1 * getme)]
+ else:
+ return [self[getme - 1]]
+ except IndexError:
+ return []
+ except ValueError:
+ range_result = self.rangePattern.search(getme)
+ if range_result:
+ start = range_result.group('start') or None
+ end = range_result.group('start') or None
+ if start:
+ start = int(start) - 1
+ if end:
+ end = int(end)
+ return self[start:end]
+
+ getme = getme.strip()
+
+ if getme.startswith(r'/') and getme.endswith(r'/'):
+ finder = re.compile(getme[1:-1], re.DOTALL | re.MULTILINE | re.IGNORECASE)
+
+ def isin(hi):
+ """Listcomp filter function for doing a regular expression search of History.
+
+ :param hi: HistoryItem
+ :return: bool - True if search matches
+ """
+ return finder.search(hi)
+ else:
+ def isin(hi):
+ """Listcomp filter function for doing a case-insensitive string search of History.
+
+ :param hi: HistoryItem
+ :return: bool - True if search matches
+ """
+ return utils.norm_fold(getme) in utils.norm_fold(hi)
+ return [itm for itm in self if isin(itm)]