mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 08:24:40 +01:00
Add functions to quote arguments for cmd.exe. This was needed for the source_cmd function.
This commit is contained in:
parent
17bf2a9a86
commit
4863a94b1c
4 changed files with 63 additions and 15 deletions
|
@ -7,10 +7,11 @@ import nose
|
||||||
from nose.tools import assert_equal, assert_true, assert_false
|
from nose.tools import assert_equal, assert_true, assert_false
|
||||||
|
|
||||||
from xonsh.lexer import Lexer
|
from xonsh.lexer import Lexer
|
||||||
from xonsh.tools import subproc_toks, subexpr_from_unbalanced, is_int, \
|
from xonsh.tools import ( subproc_toks, subexpr_from_unbalanced, is_int,
|
||||||
always_true, always_false, ensure_string, is_env_path, str_to_env_path, \
|
always_true, always_false, ensure_string, is_env_path, str_to_env_path,
|
||||||
env_path_to_str, escape_windows_title_string, is_bool, to_bool, bool_to_str, \
|
env_path_to_str, escape_windows_cmd_string, is_bool, to_bool, bool_to_str,
|
||||||
ensure_int_or_slice, is_float, is_string, check_for_partial_string
|
ensure_int_or_slice, is_float, is_string, check_for_partial_string,
|
||||||
|
argvquote )
|
||||||
|
|
||||||
LEXER = Lexer()
|
LEXER = Lexer()
|
||||||
LEXER.build()
|
LEXER.build()
|
||||||
|
@ -273,19 +274,37 @@ def test_ensure_int_or_slice():
|
||||||
obs = ensure_int_or_slice(inp)
|
obs = ensure_int_or_slice(inp)
|
||||||
yield assert_equal, exp, obs
|
yield assert_equal, exp, obs
|
||||||
|
|
||||||
def test_escape_windows_title_string():
|
|
||||||
|
def test_escape_windows_cmd_string():
|
||||||
cases = [
|
cases = [
|
||||||
('', ''),
|
('', ''),
|
||||||
('foo', 'foo'),
|
('foo', 'foo'),
|
||||||
('foo&bar', 'foo^&bar'),
|
('foo&bar', 'foo^&bar'),
|
||||||
('foo$?-/_"\\', 'foo$?-/_"\\'),
|
('foo$?-/_"\\', 'foo$?-/_^"\\'),
|
||||||
('^&<>|', '^^^&^<^>^|'),
|
('^&<>|', '^^^&^<^>^|'),
|
||||||
('this /?', 'this /.')
|
('this /?', 'this /.')
|
||||||
]
|
]
|
||||||
for st, esc in cases:
|
for st, esc in cases:
|
||||||
obs = escape_windows_title_string(st)
|
obs = escape_windows_cmd_string(st)
|
||||||
yield assert_equal, esc, obs
|
yield assert_equal, esc, obs
|
||||||
|
|
||||||
|
|
||||||
|
def test_argvquote():
|
||||||
|
cases = [
|
||||||
|
('', '""'),
|
||||||
|
('foo', 'foo'),
|
||||||
|
(r'arg1 "hallo, "world"" "\some\path with\spaces")',
|
||||||
|
r'"arg1 \"hallo, \"world\"\" \"\some\path with\spaces\")"'),
|
||||||
|
(r'"argument"2" argument3 argument4',
|
||||||
|
r'"\"argument\"2\" argument3 argument4"'),
|
||||||
|
(r'"\foo\bar bar\foo\" arg',
|
||||||
|
r'"\"\foo\bar bar\foo\\\" arg"')
|
||||||
|
]
|
||||||
|
for st, esc in cases:
|
||||||
|
obs = argvquote(st)
|
||||||
|
yield assert_equal, esc, obs
|
||||||
|
|
||||||
|
|
||||||
_leaders = ('', 'not empty')
|
_leaders = ('', 'not empty')
|
||||||
_r = ('r', '')
|
_r = ('r', '')
|
||||||
_b = ('b', '')
|
_b = ('b', '')
|
||||||
|
|
|
@ -18,6 +18,7 @@ from xonsh.replay import main as replay_main
|
||||||
from xonsh.environ import locate_binary
|
from xonsh.environ import locate_binary
|
||||||
from xonsh.foreign_shells import foreign_shell_data
|
from xonsh.foreign_shells import foreign_shell_data
|
||||||
from xonsh.vox import Vox
|
from xonsh.vox import Vox
|
||||||
|
from xonsh.tools import argvquote, escape_windows_cmd_string
|
||||||
|
|
||||||
|
|
||||||
class Aliases(MutableMapping):
|
class Aliases(MutableMapping):
|
||||||
|
@ -254,8 +255,10 @@ def source_cmd(args, stdin=None):
|
||||||
args[0] = fpath if fpath else args[0]
|
args[0] = fpath if fpath else args[0]
|
||||||
if not os.path.isfile(args[0]):
|
if not os.path.isfile(args[0]):
|
||||||
raise FileNotFoundError(args[0])
|
raise FileNotFoundError(args[0])
|
||||||
prevcmd = 'call {}'.format(' '.join(args))
|
prevcmd = 'call '
|
||||||
prevcmd += '\necho off'
|
prevcmd += ' '.join([argvquote(arg,force=True) for arg in args])
|
||||||
|
prevcmd = escape_windows_cmd_string(prevcmd)
|
||||||
|
prevcmd += '\n@echo off'
|
||||||
args.append('--prevcmd={}'.format(prevcmd))
|
args.append('--prevcmd={}'.format(prevcmd))
|
||||||
args.insert(0, 'cmd')
|
args.insert(0, 'cmd')
|
||||||
args.append('--interactive=0')
|
args.append('--interactive=0')
|
||||||
|
|
|
@ -6,7 +6,7 @@ import sys
|
||||||
import time
|
import time
|
||||||
import builtins
|
import builtins
|
||||||
|
|
||||||
from xonsh.tools import XonshError, escape_windows_title_string, ON_WINDOWS, \
|
from xonsh.tools import XonshError, escape_windows_cmd_string, ON_WINDOWS, \
|
||||||
print_exception, HAVE_PYGMENTS
|
print_exception, HAVE_PYGMENTS
|
||||||
from xonsh.completer import Completer
|
from xonsh.completer import Completer
|
||||||
from xonsh.environ import multiline_prompt, format_prompt
|
from xonsh.environ import multiline_prompt, format_prompt
|
||||||
|
@ -214,7 +214,7 @@ class BaseShell(object):
|
||||||
return
|
return
|
||||||
t = format_prompt(t)
|
t = format_prompt(t)
|
||||||
if ON_WINDOWS and 'ANSICON' not in env:
|
if ON_WINDOWS and 'ANSICON' not in env:
|
||||||
t = escape_windows_title_string(t)
|
t = escape_windows_cmd_string(t)
|
||||||
os.system('title {}'.format(t))
|
os.system('title {}'.format(t))
|
||||||
else:
|
else:
|
||||||
os.write(1, "\x1b]2;{0}\x07".format(t).encode())
|
os.write(1, "\x1b]2;{0}\x07".format(t).encode())
|
||||||
|
|
|
@ -410,17 +410,43 @@ def suggestion_sort_helper(x, y):
|
||||||
return lendiff + inx + iny
|
return lendiff + inx + iny
|
||||||
|
|
||||||
|
|
||||||
def escape_windows_title_string(s):
|
def escape_windows_cmd_string(s):
|
||||||
"""Returns a string that is usable by the Windows cmd.exe title
|
"""Returns a string that is usable by the Windows cmd.exe.
|
||||||
builtin. The escaping is based on details here and emperical testing:
|
The escaping is based on details here and emperical testing:
|
||||||
http://www.robvanderwoude.com/escapechars.php
|
http://www.robvanderwoude.com/escapechars.php
|
||||||
"""
|
"""
|
||||||
for c in '^&<>|':
|
for c in '()%!^<>&|"':
|
||||||
s = s.replace(c, '^' + c)
|
s = s.replace(c, '^' + c)
|
||||||
s = s.replace('/?', '/.')
|
s = s.replace('/?', '/.')
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def argvquote(arg, force=False):
|
||||||
|
""" It Converts arguments to a command line such
|
||||||
|
that CommandLineToArgvW will return the argument string unchanged.
|
||||||
|
Arguments in a command line should be separated by spaces; this
|
||||||
|
function does not add these spaces. This follows the suggestions outlined
|
||||||
|
here: https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
|
||||||
|
"""
|
||||||
|
if not force and len(arg) != 0 and not any([c in arg for c in ' \t\n\v"']):
|
||||||
|
cmdline = arg
|
||||||
|
else:
|
||||||
|
n_backslashes = 0
|
||||||
|
cmdline = '"'
|
||||||
|
for c in arg:
|
||||||
|
if c == '"':
|
||||||
|
cmdline += (n_backslashes * 2 + 1) * '\\'
|
||||||
|
else:
|
||||||
|
cmdline += n_backslashes * '\\'
|
||||||
|
if c != '\\':
|
||||||
|
cmdline += c
|
||||||
|
n_backslashes = 0
|
||||||
|
else:
|
||||||
|
n_backslashes += 1
|
||||||
|
cmdline += n_backslashes * 2 * '\\' + '"'
|
||||||
|
return cmdline
|
||||||
|
|
||||||
|
|
||||||
def on_main_thread():
|
def on_main_thread():
|
||||||
"""Checks if we are on the main thread or not."""
|
"""Checks if we are on the main thread or not."""
|
||||||
return threading.current_thread() is threading.main_thread()
|
return threading.current_thread() is threading.main_thread()
|
||||||
|
|
Loading…
Add table
Reference in a new issue