summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pygments/lexers/shell.py23
-rw-r--r--tests/test_shell.py52
2 files changed, 68 insertions, 7 deletions
diff --git a/pygments/lexers/shell.py b/pygments/lexers/shell.py
index df9b56f4..097ca624 100644
--- a/pygments/lexers/shell.py
+++ b/pygments/lexers/shell.py
@@ -39,12 +39,16 @@ class BashLexer(RegexLexer):
tokens = {
'root': [
include('basic'),
- (r'\$\(\(', Keyword, 'math'),
- (r'\$\(', Keyword, 'paren'),
- (r'\${#?', Keyword, 'curly'),
(r'`', String.Backtick, 'backticks'),
+ include('interp'),
include('data'),
],
+ 'interp': [
+ (r'\$\(\(', Keyword, 'math'),
+ (r'\$\(', Keyword, 'paren'),
+ (r'\${#?', String.Interpol, 'curly'),
+ (r'\$#?(\w+|.)', Name.Variable),
+ ],
'basic': [
(r'\b(if|fi|else|while|do|done|for|then|return|function|case|'
r'select|continue|until|esac|elif)(\s*)\b',
@@ -65,7 +69,8 @@ class BashLexer(RegexLexer):
(r'&&|\|\|', Operator),
],
'data': [
- (r'(?s)\$?"(\\\\|\\[0-7]+|\\.|[^"\\])*"', String.Double),
+ (r'(?s)\$?"(\\\\|\\[0-7]+|\\.|[^"\\$])*"', String.Double),
+ (r'"', String.Double, 'string'),
(r"(?s)\$?'(\\\\|\\[0-7]+|\\.|[^'\\])*'", String.Single),
(r';', Punctuation),
(r'&', Punctuation),
@@ -73,14 +78,18 @@ class BashLexer(RegexLexer):
(r'\s+', Text),
(r'\d+(?= |\Z)', Number),
(r'[^=\s\[\]{}()$"\'`\\<&|;]+', Text),
- (r'\$#?(\w+|.)', Name.Variable),
(r'<', Text),
],
+ 'string': [
+ (r'"', String.Double, '#pop'),
+ (r'(\\\\|\\[0-7]+|\\[\w\W]|[^"\\$])+', String.Double),
+ include('interp'),
+ ],
'curly': [
- (r'}', Keyword, '#pop'),
+ (r'}', String.Interpol, '#pop'),
(r':-', Keyword),
(r'\w+', Name.Variable),
- (r'[^}:"\'`$]+', Punctuation),
+ (r'[^}:"\'`$\\]+', Punctuation),
(r':', Punctuation),
include('root'),
],
diff --git a/tests/test_shell.py b/tests/test_shell.py
new file mode 100644
index 00000000..ffcf2a69
--- /dev/null
+++ b/tests/test_shell.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+"""
+ Basic Shell Tests
+ ~~~~~~~~~~~~~~~~~
+
+ :copyright: Copyright 2006-2014 by the Pygments team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import unittest
+
+from pygments.token import Token
+from pygments.lexers import BashLexer
+
+
+class BashTest(unittest.TestCase):
+
+ def setUp(self):
+ self.lexer = BashLexer()
+ self.maxDiff = None
+
+ def testCurlyNoEscapeAndQuotes(self):
+ fragment = u'echo "${a//["b"]/}"\n'
+ tokens = [
+ (Token.Name.Builtin, u'echo'),
+ (Token.Text, u' '),
+ (Token.Literal.String.Double, u'"'),
+ (Token.Keyword, u'${'),
+ (Token.Name.Variable, u'a'),
+ (Token.Punctuation, u'//['),
+ (Token.Literal.String.Double, u'"b"'),
+ (Token.Punctuation, u']/'),
+ (Token.Keyword, u'}'),
+ (Token.Literal.String.Double, u'"'),
+ (Token.Text, u'\n'),
+ ]
+ self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
+
+ def testCurlyWithEscape(self):
+ fragment = u'echo ${a//[\\"]/}\n'
+ tokens = [
+ (Token.Name.Builtin, u'echo'),
+ (Token.Text, u' '),
+ (Token.Keyword, u'${'),
+ (Token.Name.Variable, u'a'),
+ (Token.Punctuation, u'//['),
+ (Token.Literal.String.Escape, u'\\"'),
+ (Token.Punctuation, u']/'),
+ (Token.Keyword, u'}'),
+ (Token.Text, u'\n'),
+ ]
+ self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))