def test_CommandParser_incomplete(): parser = CommandParser(Choice('arg', 'all')) def check(err): eq_(err.options, Options(arg="arg")) eq_(err.errors, [ParseError("'a' is ambiguous: arg, all", Choice('arg', 'all'), 0, 1)]) with assert_raises(ArgumentError, msg=check): parser.parse('a')
def test_CommandParser_incomplete(): parser = CommandParser(Choice('arg', 'all')) def check(err): eq_(err.options, Options(arg="arg")) eq_(err.errors, [ ParseError("'a' is ambiguous: arg, all", Choice('arg', 'all'), 0, 1) ]) with assert_raises(ArgumentError, msg=check): parser.parse('a')
def test_CommandParser_with_SubParser_errors(): sub = SubArgs("num", Int("num"), abc="xyz") arg = SubParser("var", sub) parser = CommandParser(arg) def check(err): eq_(str(err), "invalid arguments: num x\n" "invalid literal for int() with base 10: 'x'") eq_(err.options, Options(var=None)) eq_(err.errors, [ParseError("invalid literal for int() with base 10: 'x'", Int("num"), 4, 5)]) with assert_raises(ArgumentError, msg=check): parser.parse('num x')
def command_decorator(func): def parse(argstr): if argstr.startswith(func.name + " "): argstr = argstr[len(func.name) + 1:] return func.arg_parser.parse(argstr) def arg_string(options): argstr = func.arg_parser.arg_string(options) if argstr: if not func.lookup_with_arg_parser: argstr = "{} {}".format(func.name, argstr) return argstr return func.name func.is_text_command = True func.name = name[0] if name else func.__name__ func.names = name or [func.__name__] func.title = title func.hotkey = hotkey func.is_enabled = is_enabled or (lambda textview, sender: True) func.arg_parser = arg_parser or CommandParser(VarArgs("args")) func.lookup_with_arg_parser = lookup_with_arg_parser func.parse = parse func.arg_string = arg_string return func
def test_CommandParser_with_SubParser(): sub = SubArgs("num", Int("n"), abc="xyz") arg = SubParser("var", sub) parser = CommandParser(arg, yesno) def test(text, result): eq_(parser.get_placeholder(text), result) yield test, "", "var ... yes" yield test, " ", "yes" yield test, " ", "" yield test, "n", "um n yes" yield test, "n ", "n yes" yield test, "num ", "n yes" yield test, "num ", "yes" def test(text, result): eq_(parser.get_completions(text), result) yield test, "", ["num"] yield test, " ", ["yes", "no"] yield test, " ", None yield test, "n", ["num"] yield test, "n ", [] yield test, "num ", [] yield test, "num ", ["yes", "no"]
def test_TextCommandController_lookup_full_command(): def test(c): m = Mocker() menu = m.mock(ak.NSMenu) ctl = TextCommandController("<history>") for command in c.commands: ctl.add_command(command, None, menu) menu.insertItem_atIndex_(ANY, ANY) eq_(ctl.lookup_full_command(c.lookup), c.result) @command(name="cm") def cmd(*args): pass @command(arg_parser=CommandParser(Int("value")), lookup_with_arg_parser=True) def num(*args): pass c = TestConfig(commands=[], lookup='cmd', result=(None, None)) yield test, c yield test, c(commands=[cmd]) yield test, c(commands=[num]) yield test, c(commands=[num], lookup='123', result=(num, Options(value=123)))
def test_CommandParser_with_SubParser_errors(): sub = SubArgs("num", Int("num"), abc="xyz") arg = SubParser("var", sub) parser = CommandParser(arg) def check(err): eq_( str(err), "invalid arguments: num x\n" "invalid literal for int() with base 10: 'x'") eq_(err.options, Options(var=None)) eq_(err.errors, [ ParseError("invalid literal for int() with base 10: 'x'", Int("num"), 4, 5) ]) with assert_raises(ArgumentError, msg=check): parser.parse('num x')
def test(c): m = Mocker() beep = m.replace(ak, 'NSBeep') @command(arg_parser=CommandParser( Choice(('selection', True), ('all', False)), Choice(('forward', False), ('reverse xyz', True), name='reverse'), Regex('sort_regex', True), )) def cmd(textview, sender, args): raise NotImplementedError("should not get here") @command(arg_parser=CommandParser( Regex('search_pattern'), Choice(('yes', True), ('no', False)), ), lookup_with_arg_parser=True) def search(textview, sender, args): raise NotImplementedError("should not get here") bar = CommandTester(cmd, search) with m: eq_(bar.get_completions(c.text), c.expect)
def test_save_options(): def test(options, hist, command=dummy_command): with replace_history() as history: mod.save_options(options, command, history) eq_(next(iter(history), None), hist) yield test, Options(value=123), "123" yield test, Options(value=None), "abc" @mod.command(arg_parser=CommandParser(Int("value", default=42))) def xyz(textview, sender, options): pass yield test, Options(value=345), "xyz 345", xyz yield test, Options(value=42), "xyz", xyz
def test(c): m = Mocker() beep = m.replace(ak, 'NSBeep') @command(arg_parser=CommandParser( Choice(('selection', True), ('all', False)), Choice(('no', False), ('yes', True)), Regex('sort_regex', True), )) def cmd(textview, sender, args): raise NotImplementedError("should not get here") @command(arg_parser=CommandParser( Regex('search_pattern', replace=c.replace), Choice(('yep', False), ('yes', True)), VarArgs("args", placeholder="..."), ), lookup_with_arg_parser=True) def search(textview, sender, args): raise NotImplementedError("should not get here") bar = CommandTester(cmd, search) with m: eq_(bar.get_placeholder(c.text), c.expect)
def test_CommandParser_order(): def test(text, result): if isinstance(result, Options): eq_(parser.parse(text), result) else: assert_raises(result, parser.parse, text) parser = CommandParser( Choice(('selection', True), ('all', False)), Choice(('forward', False), ('reverse', True), name='reverse'), ) tt = Options(selection=True, reverse=True) yield test, 'selection reverse', tt yield test, 'sel rev', tt yield test, 'rev sel', ArgumentError yield test, 'r s', ArgumentError yield test, 's r', tt yield test, 'rev', tt yield test, 'sel', Options(selection=True, reverse=False) yield test, 'r', tt yield test, 's', Options(selection=True, reverse=False)
def test_CommandParser_arg_string(): parser = CommandParser(yesno, Choice('arg', 'all')) def test(options, argstr): if isinstance(argstr, Exception): def check(err): eq_(err, argstr) with assert_raises(type(argstr), msg=check): parser.arg_string(options) else: result = parser.arg_string(options) eq_(result, argstr) yield test, Options(yes=True, arg="arg"), "" yield test, Options(yes=False, arg="arg"), "no" yield test, Options(yes=True, arg="all"), " all" yield test, Options(yes=False, arg="all"), "no all" yield test, Options(), Error("missing option: yes") yield test, Options(yes=True), Error("missing option: arg") yield test, Options(yes=None), Error("invalid value: yes=None")
) @command(title="Command Bar", hotkey=(";", ak.NSCommandKeyMask)) def show_command_bar(textview, sender, args): """Show the command bar""" from editxt import app editor = app.find_editor_with_document_view(textview.doc_view) if editor is None: ak.NSBeep() else: editor.command.activate() @command(name='goto', title="Goto Line", arg_parser=CommandParser(Int("line")), lookup_with_arg_parser=True) def goto_line(textview, sender, opts): """Jump to a line in the document""" if opts is None or opts.line is None: show_command_bar(textview, sender, None) return textview.goto_line(opts.line) @command(title="(Un)comment Selected Lines", hotkey=(",", ak.NSCommandKeyMask), is_enabled=has_selection) def comment_text(textview, sender, args): """Comment/uncomment the selected text region
BACKWARD = "BACKWARD" WRAPTOKEN = "WRAPTOKEN" REGEX = "regex" REPY = "python-replace" LITERAL = "literal" WORD = "word" @command(arg_parser=CommandParser( Regex('pattern', replace=True, default=(RegexPattern(), "")), Choice(('find-next next', 'find_next'), ('find-previous previous', 'find_previous'), ('replace-one one', 'replace_one'), ('replace-all all', 'replace_all'), ('replace-in-selection in-selection selection', 'replace_all_in_selection'), ('count-occurrences highlight', 'count_occurrences'), name='action'), Choice('regex literal word python-replace', name='search_type'), Choice(('wrap', True), ('no-wrap', False), name='wrap_around'), ), lookup_with_arg_parser=True) def find(textview, sender, args): assert args is not None, sender opts = FindOptions(**args.__dict__) save_to_find_pasteboard(opts.find_text) finder = Finder(lambda: textview, opts) return getattr(finder, args.action)(sender)
import editxt.constants as const from editxt.command.base import command, objc_delegate, SheetController from editxt.command.parser import (Choice, Regex, RegexPattern, CommandParser, Options) from editxt.commands import iterlines log = logging.getLogger(__name__) @command(name='sort', title="Sort Lines...", arg_parser=CommandParser( Choice(('selection', True), ('all', False)), Choice(('forward', False), ('reverse', True), name='reverse'), Choice(('sort-leading-whitespace', False), ('ignore-leading-whitespace', True), name='ignore_leading_whitespace'), Choice(('ignore-case', True), ('match-case', False)), Regex('sort-regex', True), )) def sort_lines(textview, sender, args): if args is None: sorter = SortLinesController(textview) sorter.begin_sheet(sender) else: sortlines(textview, args) class SortOptions(Options): DEFAULTS = dict(
import re from functools import partial from mocker import Mocker, expect, ANY, MATCH from nose.tools import eq_ from editxt.test.util import assert_raises, TestConfig from editxt.command.parser import (Choice, Int, String, Regex, RegexPattern, CommandParser, SubArgs, SubParser, VarArgs, identifier, Options, Error, ArgumentError, ParseError) log = logging.getLogger(__name__) yesno = Choice(('yes', True), ('no', False)) arg_parser = CommandParser(yesno) def test_CommandParser(): def test_parser(argstr, options, parser): if isinstance(options, Exception): def check(err): eq_(err, options) with assert_raises(type(options), msg=check): parser.parse(argstr) else: opts = parser.default_options() opts.__dict__.update(options) eq_(parser.parse(argstr), opts)
import editxt.command.base as mod from editxt.controls.textview import TextView from editxt.command.base import CommandController from editxt.command.base import SheetController, PanelController from editxt.command.parser import ArgumentError, CommandParser, Int, Options from editxt.textcommand import CommandHistory from editxt.util import KVOProxy log = logging.getLogger(__name__) @mod.command(name='abc', title='Title', hotkey=(',', 0), is_enabled=lambda *a: False, arg_parser=CommandParser(Int("value")), lookup_with_arg_parser=True) def dummy_command(textview, sender, args): assert False, "this command is not meant to be executed" def setup(controller_class, nib_name="TestController"): def setup_controller(func): @functools.wraps(func) def wrapper(): assert not hasattr(controller_class, 'COMMAND') assert not hasattr(controller_class, 'NIB_NAME') controller_class.COMMAND = dummy_command controller_class.NIB_NAME = nib_name try: func()
from editxt.command.base import command, objc_delegate, SheetController from editxt.command.parser import Choice, Int, CommandParser, Options from editxt.command.util import has_selection, iterlines log = logging.getLogger(__name__) WHITESPACE = re.compile(r"[ \t]*") @command( name='wrap', title="Hard Wrap...", hotkey=("\\", ak.NSCommandKeyMask | ak.NSShiftKeyMask), is_enabled=has_selection, arg_parser=CommandParser( # TODO test Int('wrap_column', default=const.DEFAULT_RIGHT_MARGIN), Choice(('indent', True), ('no-indent', False)), )) def wrap_lines(textview, sender, args): if args is None: wrapper = WrapLinesController(textview) wrapper.begin_sheet(sender) else: wrap_selected_lines(textview, args) @command( title="Hard Wrap At Margin", hotkey=("\\", ak.NSCommandKeyMask), arg_parser=CommandParser( # TODO test Choice(('indent', True), ('no-indent', False)), # TODO default to last used value
def test_CommandParser(): def test_parser(argstr, options, parser): if isinstance(options, Exception): def check(err): eq_(err, options) with assert_raises(type(options), msg=check): parser.parse(argstr) else: opts = parser.default_options() opts.__dict__.update(options) eq_(parser.parse(argstr), opts) test = partial(test_parser, parser=CommandParser(yesno)) yield test, "", Options(yes=True) yield test, "no", Options(yes=False) manual = SubArgs("manual", Int("bass", default=50), Int("treble", default=50)) preset = SubArgs("preset", Choice("flat", "rock", "cinema", name="value")) level = Choice(("off", 0), ('high', 4), ("medium", 2), ('low', 1), name="level") radio_parser = CommandParser( SubParser( "equalizer", manual, preset, ), level, Int("volume", default=50), #, min=0, max=100), String("name"), #, quoted=True), ) test = partial(test_parser, parser=radio_parser) yield test, "manual", Options(equalizer=(manual, Options(bass=50, treble=50))) yield test, "", Options() yield test, "preset rock low", Options(level=1, equalizer=(preset, Options(value="rock"))) yield test, " high", Options(level=0, name="high") yield test, " high", Options(level=4) yield test, "high", Options(level=4) yield test, "hi", Options(level=4) yield test, "high '' yes", ArgumentError( 'unexpected argument(s): yes', Options(volume=50, equalizer=None, name='', level=4), [], 8) def test_placeholder(argstr, expected, parser=radio_parser): eq_(parser.get_placeholder(argstr), expected) test = test_placeholder yield test, "", "equalizer ... off 50 name" yield test, " ", "50 name" yield test, " 5", " name" yield test, " 5 ", "name" yield test, " high", "" yield test, " hi", "gh 50 name" yield test, " high", " 50 name" yield test, "hi", "gh 50 name" yield test, "high ", "50 name" def make_completions_checker(argstr, expected, parser=radio_parser): eq_(parser.get_completions(argstr), expected) test = make_completions_checker yield test, "", ['manual', 'preset'] yield test, " ", [] yield test, " 5", [] yield test, " 5 ", [] yield test, " high", [] yield test, " ", ["off", "high", "medium", "low"] yield test, " hi", ["high"] parser = CommandParser(level, Int("value"), Choice("highlander", "tundra", "4runner")) test = partial(make_completions_checker, parser=parser) yield test, "h", ["high"] yield test, "t", ["tundra"] yield test, "high", ["high"] yield test, "high ", [] yield test, "high 4", [] yield test, "high x", None # ??? None indicates an error (the last token could not be consumed) ??? yield test, "high 4", ["4runner"]