Skip to content

Commit 249328e

Browse files
committed
Merge branch 'noprompt-regexp'
Closes #19 * noprompt-regexp: (57 commits) Reword defbooleantest Change hi def links Fix extant tests Clean up test fns with defbooleantest clojureRegexpEscape changes Remove unused group clojureRegexpSpecialChar Insert newly generated syntax property classes Increase synmaxcol in syntax file Vimscript literal generation for property classes Make all keyword groups vectors for consistency Aggregate property names into #'character-properties Update defs from new generation methods Refector vim-clojure-static.generate Update clj/ metadata Add display argument to some groups, organize Add \x{h..h} to clojureRegexpEscape, minor tweaks Small optimization to clojureRegexpUnicodeCharClass Use Unicode spec during generation, add shorthand classes Use (gensym)ed symbol in defsyntaxtest Fix docstring indentation ... Conflicts: syntax/clojure.vim
2 parents 9359e36 + a3429db commit 249328e

10 files changed

Lines changed: 796 additions & 105 deletions

File tree

autoload/clojurecomplete.vim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
" Last Change: 02 March 2013
77

88
" Special forms and public vars in clojure.core
9-
" Generated from https://github.com/guns/vim-clojure-static/blob/vim-release-004/vim_clojure_static.clj
10-
" Clojure 1.5.0
9+
" Generated from https://github.com/guns/vim-clojure-static/blob/vim-release-004/clj/src/vim_clojure_static/generate.clj
10+
" Clojure version 1.5.1
1111
let s:words = ["*","*'","*1","*2","*3","*agent*","*allow-unresolved-vars*","*assert*","*clojure-version*","*command-line-args*","*compile-files*","*compile-path*","*compiler-options*","*data-readers*","*default-data-reader-fn*","*e","*err*","*file*","*flush-on-newline*","*fn-loader*","*in*","*math-context*","*ns*","*out*","*print-dup*","*print-length*","*print-level*","*print-meta*","*print-readably*","*read-eval*","*source-path*","*unchecked-math*","*use-context-classloader*","*verbose-defrecords*","*warn-on-reflection*","+","+'","-","-'","->","->>","->ArrayChunk","->Vec","->VecNode","->VecSeq","-cache-protocol-fn","-reset-methods",".","..","/","<","<=","=","==",">",">=","EMPTY-NODE","accessor","aclone","add-classpath","add-watch","agent","agent-error","agent-errors","aget","alength","alias","all-ns","alter","alter-meta!","alter-var-root","amap","ancestors","and","apply","areduce","array-map","as->","aset","aset-boolean","aset-byte","aset-char","aset-double","aset-float","aset-int","aset-long","aset-short","assert","assoc!","assoc","assoc-in","associative?","atom","await","await-for","await1","bases","bean","bigdec","bigint","biginteger","binding","bit-and","bit-and-not","bit-clear","bit-flip","bit-not","bit-or","bit-set","bit-shift-left","bit-shift-right","bit-test","bit-xor","boolean","boolean-array","booleans","bound-fn","bound-fn*","bound?","butlast","byte","byte-array","bytes","case","cast","catch","char","char-array","char-escape-string","char-name-string","char?","chars","chunk","chunk-append","chunk-buffer","chunk-cons","chunk-first","chunk-next","chunk-rest","chunked-seq?","class","class?","clear-agent-errors","clojure-version","coll?","comment","commute","comp","comparator","compare","compare-and-set!","compile","complement","concat","cond","cond->","cond->>","condp","conj!","conj","cons","constantly","construct-proxy","contains?","count","counted?","create-ns","create-struct","cycle","dec","dec'","decimal?","declare","def","default-data-readers","definline","definterface","defmacro","defmethod","defmulti","defn","defn-","defonce","defprotocol","defrecord","defstruct","deftype","delay","delay?","deliver","denominator","deref","derive","descendants","destructure","disj!","disj","dissoc!","dissoc","distinct","distinct?","do","doall","dorun","doseq","dosync","dotimes","doto","double","double-array","doubles","drop","drop-last","drop-while","empty","empty?","ensure","enumeration-seq","error-handler","error-mode","eval","even?","every-pred","every?","ex-data","ex-info","extend","extend-protocol","extend-type","extenders","extends?","false?","ffirst","file-seq","filter","filterv","finally","find","find-keyword","find-ns","find-protocol-impl","find-protocol-method","find-var","first","flatten","float","float-array","float?","floats","flush","fn","fn","fn?","fnext","fnil","for","force","format","frequencies","future","future-call","future-cancel","future-cancelled?","future-done?","future?","gen-class","gen-interface","gensym","get","get-in","get-method","get-proxy-class","get-thread-bindings","get-validator","group-by","hash","hash-combine","hash-map","hash-set","identical?","identity","if","if-let","if-not","ifn?","import","in-ns","inc","inc'","init-proxy","instance?","int","int-array","integer?","interleave","intern","interpose","into","into-array","ints","io!","isa?","iterate","iterator-seq","juxt","keep","keep-indexed","key","keys","keyword","keyword?","last","lazy-cat","lazy-seq","let","let","letfn","line-seq","list","list*","list?","load","load-file","load-reader","load-string","loaded-libs","locking","long","long-array","longs","loop","loop","macroexpand","macroexpand-1","make-array","make-hierarchy","map","map-indexed","map?","mapcat","mapv","max","max-key","memfn","memoize","merge","merge-with","meta","method-sig","methods","min","min-key","mod","monitor-enter","monitor-exit","munge","name","namespace","namespace-munge","neg?","new","newline","next","nfirst","nil?","nnext","not","not-any?","not-empty","not-every?","not=","ns","ns-aliases","ns-imports","ns-interns","ns-map","ns-name","ns-publics","ns-refers","ns-resolve","ns-unalias","ns-unmap","nth","nthnext","nthrest","num","number?","numerator","object-array","odd?","or","parents","partial","partition","partition-all","partition-by","pcalls","peek","persistent!","pmap","pop!","pop","pop-thread-bindings","pos?","pr","pr-str","prefer-method","prefers","primitives-classnames","print","print-ctor","print-dup","print-method","print-simple","print-str","printf","println","println-str","prn","prn-str","promise","proxy","proxy-call-with-super","proxy-mappings","proxy-name","proxy-super","push-thread-bindings","pvalues","quot","quote","rand","rand-int","rand-nth","range","ratio?","rational?","rationalize","re-find","re-groups","re-matcher","re-matches","re-pattern","re-seq","read","read-line","read-string","realized?","recur","reduce","reduce-kv","reduced","reduced?","reductions","ref","ref-history-count","ref-max-history","ref-min-history","ref-set","refer","refer-clojure","reify","release-pending-sends","rem","remove","remove-all-methods","remove-method","remove-ns","remove-watch","repeat","repeatedly","replace","replicate","require","reset!","reset-meta!","resolve","rest","restart-agent","resultset-seq","reverse","reversible?","rseq","rsubseq","satisfies?","second","select-keys","send","send-off","send-via","seq","seq?","seque","sequence","sequential?","set!","set","set-agent-send-executor!","set-agent-send-off-executor!","set-error-handler!","set-error-mode!","set-validator!","set?","short","short-array","shorts","shuffle","shutdown-agents","slurp","some","some->","some->>","some-fn","sort","sort-by","sorted-map","sorted-map-by","sorted-set","sorted-set-by","sorted?","special-symbol?","spit","split-at","split-with","str","string?","struct","struct-map","subs","subseq","subvec","supers","swap!","symbol","symbol?","sync","take","take-last","take-nth","take-while","test","the-ns","thread-bound?","throw","time","to-array","to-array-2d","trampoline","transient","tree-seq","true?","try","type","unchecked-add","unchecked-add-int","unchecked-byte","unchecked-char","unchecked-dec","unchecked-dec-int","unchecked-divide-int","unchecked-double","unchecked-float","unchecked-inc","unchecked-inc-int","unchecked-int","unchecked-long","unchecked-multiply","unchecked-multiply-int","unchecked-negate","unchecked-negate-int","unchecked-remainder-int","unchecked-short","unchecked-subtract","unchecked-subtract-int","underive","unquote","unquote-splicing","update-in","update-proxy","use","val","vals","var","var-get","var-set","var?","vary-meta","vec","vector","vector-of","vector?","when","when-first","when-let","when-not","while","with-bindings","with-bindings*","with-in-str","with-loading-context","with-local-vars","with-meta","with-open","with-out-str","with-precision","with-redefs","with-redefs-fn","xml-seq","zero?","zipmap"]
1212

1313
" Simple word completion omnifunc

clj/.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/target
2+
/lib
3+
/classes
4+
/checkouts
5+
pom.xml
6+
pom.xml.asc
7+
*.jar
8+
*.class
9+
.lein-deps-sum
10+
.lein-failures
11+
.lein-plugins
12+
.lein-repl-history
13+
/tmp

clj/project.clj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
(defproject vim-clojure-static "0.1.0"
2+
:description "Utilities and tests for Vim's Clojure runtime files."
3+
:url "https://github.com/guns/vim-clojure-static"
4+
:license {:name "Vim License"
5+
:url "http://vimdoc.sourceforge.net/htmldoc/uganda.html#license"
6+
:comments ":help license"}
7+
:dependencies [[org.clojure/clojure "1.5.1"]])
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
;; Authors: Sung Pae <self@sungpae.com>
2+
;; Joel Holdbrooks <cjholdbrooks@gmail.com>
3+
4+
(ns vim-clojure-static.generate
5+
(:require [clojure.string :as string]
6+
[clojure.set :as set]))
7+
8+
;;
9+
;; Helpers
10+
;;
11+
12+
(defn property-pattern
13+
"Vimscript very magic pattern for a character property class."
14+
([s] (property-pattern s true))
15+
([s braces?] (if braces?
16+
(format "\\v\\\\[pP]\\{%s\\}" s)
17+
(format "\\v\\\\[pP]%s" s))))
18+
19+
(defn syntax-match-properties
20+
"Vimscript literal `syntax match` for a character property class."
21+
([group fmt props] (syntax-match-properties group fmt props true))
22+
([group fmt props braces?]
23+
(format "syntax match %s \"%s\" contained display\n"
24+
(name group)
25+
(property-pattern (format fmt (string/join \| (sort props))) braces?))))
26+
27+
(defn get-private-field
28+
"Violate encapsulation and get the value of a private field."
29+
[cls fieldname]
30+
(let [field (first (filter #(= fieldname (.getName %)) (.getDeclaredFields cls)))]
31+
(.setAccessible field true)
32+
(.get field field)))
33+
34+
;;
35+
;; Definitions
36+
;;
37+
38+
(def generation-comment
39+
"\" Generated from https://github.com/guns/vim-clojure-static/blob/vim-release-004/clj/src/vim_clojure_static/generate.clj\n")
40+
41+
(def clojure-version-comment
42+
(format "\" Clojure version %s\n" (clojure-version)))
43+
44+
(def java-version-comment
45+
(format "\" Java version %s\n" (System/getProperty "java.version")))
46+
47+
(def special-forms
48+
"http://clojure.org/special_forms"
49+
'[def if do let quote var fn loop recur throw try catch finally
50+
monitor-enter monitor-exit . new set!])
51+
52+
(def keyword-groups
53+
"Special forms, constants, and every public var in clojure.core listed by
54+
syntax group suffix."
55+
(let [builtins [["Constant" '[nil]]
56+
["Boolean" '[true false]]
57+
["Special" special-forms]
58+
;; The duplicates from Special are intentional here
59+
["Exception" '[throw try catch finally]]
60+
["Cond" '[case cond cond-> cond->> condp if-let if-not when
61+
when-first when-let when-not]]
62+
;; Imperative looping constructs (not sequence functions)
63+
["Repeat" '[doall dorun doseq dotimes while]]]
64+
declared (atom (set (filter symbol? (mapcat peek builtins))))
65+
coresyms (keys (ns-publics `clojure.core))
66+
select! (fn [pred]
67+
(let [xs (set/difference (set (filter pred coresyms)) @declared)]
68+
(swap! declared into xs)
69+
(vec xs)))]
70+
(conj builtins
71+
;; Clojure devs are fastidious about accurate metadata
72+
["Define" (select! #(re-seq #"\Adef(?!ault)" (str %)))]
73+
["Macro" (select! #(:macro (meta (resolve %))))]
74+
["Func" (select! #(:arglists (meta (resolve %))))]
75+
["Variable" (select! identity)])))
76+
77+
(def character-properties
78+
"Character property names derived via reflection."
79+
(let [props (map (fn [[p typ]] [p (string/replace (.getName (type typ)) #".*\$(.+)" "$1")])
80+
(get-private-field java.util.regex.Pattern$CharPropertyNames "map"))
81+
props (map (fn [[typ ps]] [typ (map first ps)])
82+
(group-by peek props))
83+
props (into {} props)
84+
binary (concat (map #(. % name) (get-private-field java.util.regex.UnicodeProp "$VALUES"))
85+
(keys (get-private-field java.util.regex.UnicodeProp "aliases")))
86+
script (concat (map #(. % name) (java.lang.Character$UnicodeScript/values))
87+
(keys (get-private-field java.lang.Character$UnicodeScript "aliases")))
88+
block (keys (get-private-field java.lang.Character$UnicodeBlock "map"))]
89+
;;
90+
;; * The keys "1"…"5" reflect the order of CharPropertyFactory
91+
;; declarations in Pattern.java!
92+
;;
93+
;; * The "L1" (Latin-1) category is not defined by Unicode and exists
94+
;; merely as an alias for the first 8 bits of code points.
95+
;;
96+
;; * The "all" category is the Unicode "Any" category by a different name,
97+
;; and thus excluded.
98+
;;
99+
{:posix (disj (set (mapcat (partial get props) ["2" "3"])) "L1")
100+
:java (set (get props "4"))
101+
:binary (set binary)
102+
:category (set (get props "1"))
103+
:script (set script)
104+
:block (set block)}))
105+
106+
;;
107+
;; Vimscript literals
108+
;;
109+
110+
(def vim-syntax-keywords
111+
"Vimscript literal `syntax keyword` definitions."
112+
(let [names (fn [coll]
113+
(reduce (fn [v x]
114+
;; Include fully qualified versions of core vars
115+
(cond (symbol? x) (if-let [m (meta (resolve x))]
116+
(conj v (str (:name m)) (str (:ns m) \/ (:name m)))
117+
(conj v (str x)))
118+
(nil? x) (conj v "nil")
119+
:else (conj v (str x))))
120+
[] coll))
121+
definitions (map (fn [[group keywords]]
122+
(format "syntax keyword clojure%s %s\n"
123+
group
124+
(string/join \space (sort (names keywords)))))
125+
keyword-groups)]
126+
(string/join definitions)))
127+
128+
(def vim-completion-words
129+
"Vimscript literal list of words for omnifunc completion."
130+
(format "let s:words = [%s]\n"
131+
(->> `clojure.core
132+
ns-publics
133+
keys
134+
(concat special-forms)
135+
(map #(str \" % \"))
136+
sort
137+
(string/join \,))))
138+
139+
(def vim-posix-char-classes
140+
"Vimscript literal `syntax match` for POSIX character classes."
141+
;; `IsPosix` works, but is undefined.
142+
(syntax-match-properties
143+
:clojureRegexpPosixCharClass
144+
"%%(%s)"
145+
(:posix character-properties)))
146+
147+
(def vim-java-char-classes
148+
"Vimscript literal `syntax match` for \\p{javaMethod} property classes."
149+
;; `IsjavaMethod` works, but is undefined.
150+
(syntax-match-properties
151+
:clojureRegexpJavaCharClass
152+
"java%%(%s)"
153+
(map #(string/replace % #"\Ajava" "") (:java character-properties))))
154+
155+
(def vim-unicode-binary-char-classes
156+
"Vimscript literal `syntax match` for Unicode Binary properties."
157+
;; Though the docs do not mention it, the property name is matched case
158+
;; insensitively like the other Unicode properties.
159+
(syntax-match-properties
160+
:clojureRegexpUnicodeCharClass
161+
"\\cIs%%(%s)"
162+
(map string/lower-case (:binary character-properties))))
163+
164+
(def vim-unicode-category-char-classes
165+
"Vimscript literal `syntax match` for Unicode General Category classes."
166+
(let [cats (map seq (:category character-properties))
167+
cats (map (fn [[c subcats]]
168+
(format "%s[%s]" c (apply str (sort (mapcat rest subcats)))))
169+
(group-by first cats))]
170+
;; gc= and general_category= can be case insensitive, but this is behavior
171+
;; is undefined.
172+
(str
173+
(syntax-match-properties
174+
:clojureRegexpUnicodeCharClass
175+
"%%(%s)"
176+
(sort (filter #(= (count %) 1) (:category character-properties)))
177+
false)
178+
(syntax-match-properties
179+
:clojureRegexpUnicodeCharClass
180+
"%%(Is|gc\\=|general_category\\=)?%%(%s)"
181+
cats))))
182+
183+
(def vim-unicode-script-char-classes
184+
"Vimscript literal `syntax match` for Unicode Script properties."
185+
;; Script names are matched case insensitively, but Is, sc=, and script=
186+
;; should be matched exactly. In this case, only Is is matched exactly, but
187+
;; this is an acceptable trade-off.
188+
;;
189+
;; InScriptName works, but is undefined.
190+
(syntax-match-properties
191+
:clojureRegexpUnicodeCharClass
192+
"\\c%%(Is|sc\\=|script\\=)%%(%s)"
193+
(map string/lower-case (:script character-properties))))
194+
195+
(def vim-unicode-block-char-classes
196+
"Vimscript literal `syntax match` for Unicode Block properties."
197+
;; Block names work like Script names, except the In prefix is used in place
198+
;; of Is.
199+
(syntax-match-properties
200+
:clojureRegexpUnicodeCharClass
201+
"\\c%%(In|blk\\=|block\\=)%%(%s)"
202+
(map string/lower-case (:block character-properties))))
203+
204+
(comment
205+
(spit "tmp/clojure-defs.vim"
206+
(str generation-comment
207+
clojure-version-comment
208+
vim-syntax-keywords
209+
\newline
210+
generation-comment
211+
clojure-version-comment
212+
vim-completion-words
213+
\newline
214+
generation-comment
215+
java-version-comment
216+
vim-posix-char-classes
217+
vim-java-char-classes
218+
vim-unicode-binary-char-classes
219+
vim-unicode-category-char-classes
220+
vim-unicode-script-char-classes
221+
vim-unicode-block-char-classes)))
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
;; Authors: Sung Pae <self@sungpae.com>
2+
3+
(ns vim-clojure-static.test
4+
(:require [clojure.java.io :as io]
5+
[clojure.java.shell :as shell]
6+
[clojure.edn :as edn]
7+
[clojure.string :as string]
8+
[clojure.test :as test]))
9+
10+
(defn syn-id-names
11+
"Map lines of clojure text to vim synID names at each column as keywords:
12+
13+
(syn-id-names \"foo\" …) -> {\"foo\" [:clojureString :clojureString :clojureString] …}
14+
15+
First parameter is the file that is used to communicate with Vim. The file
16+
is not deleted to allow manual inspection."
17+
[file & lines]
18+
(io/make-parents file)
19+
(spit file (string/join \newline lines))
20+
(shell/sh "vim" "-u" "NONE" "-N" "-S" "vim/syn-id-names.vim" file)
21+
;; The last line of the file will contain valid EDN
22+
(into {} (map (fn [l ids] [l (mapv keyword ids)])
23+
lines
24+
(edn/read-string (peek (string/split-lines (slurp file)))))))
25+
26+
(defn subfmt
27+
"Extract a subsequence of seq s corresponding to the character positions of
28+
%s in format spec fmt"
29+
[fmt s]
30+
(let [f (seq (format fmt \o001))
31+
i (.indexOf f \o001)]
32+
(->> s
33+
(drop i)
34+
(drop-last (- (count f) i 1)))))
35+
36+
(defmacro defsyntaxtest
37+
"Create a new testing var with tests in the format:
38+
39+
(defsyntaxtest example
40+
(with-format \"#\\\"%s\\\"\"
41+
\"123\" #(every? (partial = :clojureRegexp) %)
42+
…)
43+
(with-format …))
44+
45+
At runtime the syn-id-names of the strings (which are placed in the format
46+
spec) are passed to their associated predicates. The format spec should
47+
contain a single `%s`."
48+
[name & body]
49+
(assert (every? #(= 'with-format (first %)) body))
50+
(assert (every? #(string? (second %)) body))
51+
(assert (every? #(even? (count %)) body))
52+
(let [[strings contexts] (reduce (fn [[strings contexts] [_ fmt & forms]]
53+
(let [[ss λs] (apply map list (partition 2 forms))
54+
ss (map #(format fmt %) ss)]
55+
[(concat strings ss)
56+
(conj contexts {:fmt fmt :ss ss :λs λs})]))
57+
[[] []] body)
58+
syntable (gensym "syntable")]
59+
`(test/deftest ~name
60+
;; Shellout to vim should happen at runtime
61+
(let [~syntable (syn-id-names (str "tmp/" ~(str name) ".clj") ~@strings)]
62+
~@(map (fn [{:keys [fmt ss λs]}]
63+
`(test/testing ~fmt
64+
~@(map (fn [s λ] `(test/is ( (subfmt ~fmt (get ~syntable ~s)))))
65+
ss λs)))
66+
contexts)))))
67+
68+
(comment
69+
70+
(macroexpand-1
71+
'(defsyntaxtest number-literals-test
72+
(with-format "%s"
73+
"123" #(every? (partial = :clojureNumber) %)
74+
"456" #(every? (partial = :clojureNumber) %))
75+
(with-format "#\"%s\""
76+
"^" #(= % [:clojureRegexpBoundary]))))
77+
(test #'number-literals-test)
78+
79+
)

0 commit comments

Comments
 (0)