diff --git a/CHANGES.md b/CHANGES.md
index b43a548aee..da9423a0c6 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -5,7 +5,15 @@ Grammars:
- fix(python) Fix recognition of numeric literals followed by keywords without whitespace (#2985) [Richard Gibson][]
- enh(swift) add SE-0290 unavailability condition (#3382) [Bradley Mackey][]
- enh(java) add `sealed` and `non-sealed` keywords (#3386) [Bradley Mackey][]
-- fix(clojure) `comment` macro catches more than it should [Björn Ebbinghaus][]
+- fix(clojure) Several issues with Clojure highlighting (#3397) [Björn Ebbinghaus][]
+ - fix(clojure) `comment` macro catches more than it should (#3395)
+ - fix(clojure) `$` in symbol breaks highlighting
+ - fix(clojure) Add complete regex for number detection
+ - enh(clojure) Add character mode for character literals
+ - fix(clojure) Inconsistent namespaced map highlighting
+ - enh(clojure) Add `regex` mode to regex literal
+ - fix(clojure) Remove inconsistent/broken highlighting for metadata
+ - enh(clojure) Add `punctuation` mode for commas.
[Richard Gibson]: https://github.com/gibson042
[Bradley Mackey]: https://github.com/bradleymackey
diff --git a/src/languages/clojure.js b/src/languages/clojure.js
index 34c9ff18af..34a4dc7fe4 100644
--- a/src/languages/clojure.js
+++ b/src/languages/clojure.js
@@ -8,8 +8,8 @@ Category: lisp
/** @type LanguageFn */
export default function(hljs) {
- const SYMBOLSTART = 'a-zA-Z_\\-!.?+*=<>\'';
- const SYMBOL_RE = '[' + SYMBOLSTART + '][' + SYMBOLSTART + '0-9/;:]*';
+ const SYMBOLSTART = 'a-zA-Z_\\-!.?+*=<>&\'';
+ const SYMBOL_RE = '[#]?[' + SYMBOLSTART + '][' + SYMBOLSTART + '0-9/;:$#]*';
const globals = 'def defonce defprotocol defstruct defmulti defmethod defn- defn defmacro deftype defrecord';
const keywords = {
$pattern: SYMBOL_RE,
@@ -45,20 +45,44 @@ export default function(hljs) {
'lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize'
};
- const SIMPLE_NUMBER_RE = '[-+]?\\d+(\\.\\d+)?';
-
const SYMBOL = {
begin: SYMBOL_RE,
relevance: 0
};
const NUMBER = {
- className: 'number',
- begin: SIMPLE_NUMBER_RE,
- relevance: 0
+ scope: 'number',
+ relevance: 0,
+ variants: [
+ {match: /[-+]?0[xX][0-9a-fA-F]+N?/}, // hexadecimal // 0x2a
+ {match: /[-+]?0[0-7]+N?/}, // octal // 052
+ {match: /[-+]?[1-9][0-9]?[rR][0-9a-zA-Z]+N?/}, // variable radix from 2 to 36 // 2r101010, 8r52, 36r16
+ {match: /[-+]?[0-9]+\/[0-9]+N?/}, // ratio // 1/2
+ {match: /[-+]?[0-9]+((\.[0-9]*([eE][+-]?[0-9]+)?M?)|([eE][+-]?[0-9]+M?|M))/}, // float // 0.42 4.2E-1M 42E1 42M
+ {match: /[-+]?([1-9][0-9]*|0)N?/}, // int (don't match leading 0) // 42 42N
+ ]
};
+ const CHARACTER = {
+ scope: 'character',
+ variants: [
+ {match: /\\o[0-3]?[0-7]{1,2}/}, // Unicode Octal 0 - 377
+ {match: /\\u[0-9a-fA-F]{4}/}, // Unicode Hex 0000 - FFFF
+ {match: /\\(newline|space|tab|formfeed|backspace|return)/}, // special characters
+ {match: /\\\S/, relevance: 0} // any non-whitespace char
+ ]
+ }
+ const REGEX = {
+ scope: 'regex',
+ begin: /#"/,
+ end: /"/
+ }
const STRING = hljs.inherit(hljs.QUOTE_STRING_MODE, {
illegal: null
});
+ const COMMA = {
+ scope: 'punctuation',
+ match: /,/,
+ relevance: 0
+ }
const COMMENT = hljs.COMMENT(
';',
'$',
@@ -71,15 +95,10 @@ export default function(hljs) {
begin: /\b(true|false|nil)\b/
};
const COLLECTION = {
- begin: '[\\[\\{]',
+ begin: "\\[|(#::?" + SYMBOL_RE + ")?\\{",
end: '[\\]\\}]',
relevance: 0
};
- const HINT = {
- className: 'comment',
- begin: '\\^' + SYMBOL_RE
- };
- const HINT_COL = hljs.COMMENT('\\^\\{', '\\}');
const KEY = {
className: 'symbol',
begin: '[:]{1,2}' + SYMBOL_RE
@@ -100,10 +119,11 @@ export default function(hljs) {
starts: BODY
};
const DEFAULT_CONTAINS = [
+ COMMA,
LIST,
+ CHARACTER,
+ REGEX,
STRING,
- HINT,
- HINT_COL,
COMMENT,
KEY,
COLLECTION,
@@ -138,17 +158,17 @@ export default function(hljs) {
];
BODY.contains = DEFAULT_CONTAINS;
COLLECTION.contains = DEFAULT_CONTAINS;
- HINT_COL.contains = [ COLLECTION ];
return {
name: 'Clojure',
aliases: [ 'clj', 'edn' ],
illegal: /\S/,
contains: [
+ COMMA,
LIST,
+ CHARACTER,
+ REGEX,
STRING,
- HINT,
- HINT_COL,
COMMENT,
KEY,
COLLECTION,
diff --git a/test/markup/clojure/character.expect.txt b/test/markup/clojure/character.expect.txt
new file mode 100644
index 0000000000..1b7cf05082
--- /dev/null
+++ b/test/markup/clojure/character.expect.txt
@@ -0,0 +1,5 @@
+\A
+\a
+\formfeed
+\u00DF
+\o303
\ No newline at end of file
diff --git a/test/markup/clojure/character.txt b/test/markup/clojure/character.txt
new file mode 100644
index 0000000000..7cf4531ab9
--- /dev/null
+++ b/test/markup/clojure/character.txt
@@ -0,0 +1,5 @@
+\A
+\a
+\formfeed
+\u00DF
+\o303
\ No newline at end of file
diff --git a/test/markup/clojure/deps_edn.expect.txt b/test/markup/clojure/deps_edn.expect.txt
index fdedd183bd..9d36af63ad 100644
--- a/test/markup/clojure/deps_edn.expect.txt
+++ b/test/markup/clojure/deps_edn.expect.txt
@@ -1,14 +1,14 @@
-{:aliases {:export {:exec-fn stelcodes.dev-blog.generator/export},
- :repl {:extra-deps {cider/cider-nrepl {:mvn/version "0.25.2"},
- nrepl/nrepl {:mvn/version "0.8.3"}},
- :extra-paths ["dev"],
+{:aliases {:export {:exec-fn stelcodes.dev-blog.generator/export},
+ :repl {:extra-deps {cider/cider-nrepl {:mvn/version "0.25.2"},
+ nrepl/nrepl {:mvn/version "0.8.3"}},
+ :extra-paths ["dev"],
:main-opts ["-m"
"nrepl.cmdline"
"--middleware"
"[cider.nrepl/cider-middleware]"
- "--interactive"]},
- :webhook {:exec-fn stelcodes.dev-blog.webhook/listen}},
- :deps {http-kit/http-kit {:mvn/version "2.5.3"},
- org.clojure/clojure {:mvn/version "1.10.1"},
- stasis/stasis {:mvn/version "2.5.1"}},
+ "--interactive"]},
+ :webhook {:exec-fn stelcodes.dev-blog.webhook/listen}},
+ :deps {http-kit/http-kit {:mvn/version "2.5.3"},
+ org.clojure/clojure {:mvn/version "1.10.1"},
+ stasis/stasis {:mvn/version "2.5.1"}},
:paths ["src" "resources"]}
diff --git a/test/markup/clojure/globals_definition.expect.txt b/test/markup/clojure/globals_definition.expect.txt
index e387a1b63c..93ce3c17a2 100644
--- a/test/markup/clojure/globals_definition.expect.txt
+++ b/test/markup/clojure/globals_definition.expect.txt
@@ -5,8 +5,8 @@
(defn clojure-function [args]
(let [string "multiline\nstring"
- regexp #"regexp"
- number 100,000
+ regexp #"regexp"
+ number 100000
booleans [false true]
keyword ::the-keyword]
@@ -14,12 +14,17 @@
(->>
(list [vector] {:map map} #{'set})))))
+#:person{:first "Han"
+ :last "Solo"
+ :ship #:ship{:name "Millenium Falcon"}}
+#::{:a 1, :b 2}
+
(def some-var)
(def alternative-var "132")
-(defonce ^:private another-var #"foo")
+(defonce ^:private another-var #"foo")
(defn- add [x y] (+ x y))
@@ -58,4 +63,4 @@
(def myCircle (Circle. 10))
-(def mySquare (Square. 5 11))
+(def mySquare (Square. 5 11))
\ No newline at end of file
diff --git a/test/markup/clojure/globals_definition.txt b/test/markup/clojure/globals_definition.txt
index 6faeee7942..fadd808156 100644
--- a/test/markup/clojure/globals_definition.txt
+++ b/test/markup/clojure/globals_definition.txt
@@ -6,7 +6,7 @@
(defn clojure-function [args]
(let [string "multiline\nstring"
regexp #"regexp"
- number 100,000
+ number 100000
booleans [false true]
keyword ::the-keyword]
;; this is comment
@@ -14,6 +14,11 @@
(->>
(list [vector] {:map map} #{'set})))))
+#:person{:first "Han"
+ :last "Solo"
+ :ship #:ship{:name "Millenium Falcon"}}
+#::{:a 1, :b 2}
+
; global
(def some-var)
; another one
diff --git a/test/markup/clojure/hint_col.expect.txt b/test/markup/clojure/hint_col.expect.txt
deleted file mode 100644
index cb833d9027..0000000000
--- a/test/markup/clojure/hint_col.expect.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-(import [java.lang.annotation Retention RetentionPolicy Target ElementType]
- [javax.xml.ws WebServiceRef WebServiceRefs])
-
-(definterface Foo (foo []))
-
-
-(deftype
- Bar [ a
-
-
- b]
-
- Foo (
- foo [this] 42))
-
-(seq (.getAnnotations Bar))
-(seq (.getAnnotations (.getField Bar "b")))
-(seq (.getAnnotations (.getMethod Bar "foo" nil)))
diff --git a/test/markup/clojure/hint_col.txt b/test/markup/clojure/hint_col.txt
deleted file mode 100644
index 9584dec9d0..0000000000
--- a/test/markup/clojure/hint_col.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-(import [java.lang.annotation Retention RetentionPolicy Target ElementType]
- [javax.xml.ws WebServiceRef WebServiceRefs])
-
-(definterface Foo (foo []))
-
-;; annotation on type
-(deftype ^{Deprecated true
- Retention RetentionPolicy/RUNTIME
- javax.annotation.processing.SupportedOptions ["foo" "bar" "baz"]
- javax.xml.ws.soap.Addressing {:enabled false :required true}
- WebServiceRefs [(WebServiceRef {:name "fred" :type String})
- (WebServiceRef {:name "ethel" :mappedName "lucy"})]}
- Bar [^int a
- ;; on field
- ^{:tag int
- Deprecated true
- Retention RetentionPolicy/RUNTIME
- javax.annotation.processing.SupportedOptions ["foo" "bar" "baz"]
- javax.xml.ws.soap.Addressing {:enabled false :required true}
- WebServiceRefs [(WebServiceRef {:name "fred" :type String})
- (WebServiceRef {:name "ethel" :mappedName "lucy"})]}
- b]
- ;; on method
- Foo (^{Deprecated true
- Retention RetentionPolicy/RUNTIME
- javax.annotation.processing.SupportedOptions ["foo" "bar" "baz"]
- javax.xml.ws.soap.Addressing {:enabled false :required true}
- WebServiceRefs [(WebServiceRef {:name "fred" :type String})
- (WebServiceRef {:name "ethel" :mappedName "lucy"})]}
- foo [this] 42))
-
-(seq (.getAnnotations Bar))
-(seq (.getAnnotations (.getField Bar "b")))
-(seq (.getAnnotations (.getMethod Bar "foo" nil)))
diff --git a/test/markup/clojure/number.expect.txt b/test/markup/clojure/number.expect.txt
new file mode 100644
index 0000000000..25bb636d60
--- /dev/null
+++ b/test/markup/clojure/number.expect.txt
@@ -0,0 +1,69 @@
+
+00
+42
++42
+-42
+
+
+42N
+0N
++42N
+-42N
+
+
+052
+00N
++052
+-00N
+
+
+0x2a
+0x0N
++0x2a
+-0x0N
+
+
+2r101010
+8r52
+16r2a
+36r16
+-2r101010
++36r16
+
+
+2r101010N
+8r52N
+16r2aN
+36r16N
++8r52N
+-16r2aN
+
+
+1/2
+-1/2
++123/224
+
+
+42.0
+-42.0
++42.0
+42.
++42.
+-42.
+
+
+42.0M
+-42M
+42.M
+42M
+
+
+42.0E2
+-42.0E+9
+42E-0
++42E-0
+
+42.0E2M
+42E+9M
+-42E+9M
++42.0E2M
\ No newline at end of file
diff --git a/test/markup/clojure/number.txt b/test/markup/clojure/number.txt
new file mode 100644
index 0000000000..01a0374c09
--- /dev/null
+++ b/test/markup/clojure/number.txt
@@ -0,0 +1,69 @@
+; integer
+00
+42
++42
+-42
+
+; BigInt
+42N
+0N
++42N
+-42N
+
+; octal
+052
+00N
++052
+-00N
+
+; hex
+0x2a
+0x0N
++0x2a
+-0x0N
+
+; radix
+2r101010
+8r52
+16r2a
+36r16
+-2r101010
++36r16
+
+; radix BigInt
+2r101010N
+8r52N
+16r2aN
+36r16N
++8r52N
+-16r2aN
+
+;; ratios
+1/2
+-1/2
++123/224
+
+;; floats
+42.0
+-42.0
++42.0
+42.
++42.
+-42.
+
+; BigDecimal
+42.0M
+-42M
+42.M
+42M
+
+; with Exponent
+42.0E2
+-42.0E+9
+42E-0
++42E-0
+
+42.0E2M
+42E+9M
+-42E+9M
++42.0E2M
\ No newline at end of file
diff --git a/test/markup/clojure/symbols-numbers.expect.txt b/test/markup/clojure/symbols-numbers.expect.txt
index 87595d111b..7813d22876 100644
--- a/test/markup/clojure/symbols-numbers.expect.txt
+++ b/test/markup/clojure/symbols-numbers.expect.txt
@@ -1 +1,4 @@
(def +x [(a 1) +2 -3.0 y-5])
+(System/getProperty "java.vm.version")
+(.getEnclosingClass java.util.Map$Entry)
+(java.util.Map$Entry. .getEnclosingClass)
diff --git a/test/markup/clojure/symbols-numbers.txt b/test/markup/clojure/symbols-numbers.txt
index 01e839b555..97c92bb562 100644
--- a/test/markup/clojure/symbols-numbers.txt
+++ b/test/markup/clojure/symbols-numbers.txt
@@ -1 +1,4 @@
(def +x [(a 1) +2 -3.0 y-5])
+(System/getProperty "java.vm.version")
+(.getEnclosingClass java.util.Map$Entry)
+(java.util.Map$Entry. .getEnclosingClass)
\ No newline at end of file