swagr 0.0.8 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +20 -0
- data/bin/swagr +37 -9
- data/examples/examples01/app.rb +5 -1
- data/examples/examples01/views/edit.slim +31 -0
- data/examples/examples01/views/footer.slim +1 -1
- data/examples/examples01/views/layout.slim +23 -5
- data/examples/examples01/views/navbar.slim +17 -16
- data/lib/swagr/version.rb +3 -1
- data/templates/app.rb +5 -1
- data/templates/static/js/codemirror/keymap/vim.js +279 -66
- data/templates/static/js/codemirror/lib/codemirror.css +10 -9
- data/templates/static/js/codemirror/lib/codemirror.js +385 -152
- data/templates/static/js/codemirror/mode/apl/apl.js +160 -0
- data/templates/static/js/codemirror/mode/apl/index.html +61 -0
- data/templates/static/js/codemirror/mode/asterisk/asterisk.js +183 -0
- data/templates/static/js/codemirror/mode/asterisk/index.html +142 -0
- data/templates/static/js/codemirror/mode/clike/clike.js +2 -0
- data/templates/static/js/codemirror/mode/clike/index.html +1 -1
- data/templates/static/js/codemirror/mode/clike/scala.html +1 -1
- data/templates/static/js/codemirror/mode/clojure/clojure.js +3 -3
- data/templates/static/js/codemirror/mode/css/css.js +2 -2
- data/templates/static/js/codemirror/mode/css/test.js +76 -471
- data/templates/static/js/codemirror/mode/d/d.js +205 -0
- data/templates/static/js/codemirror/mode/d/index.html +262 -0
- data/templates/static/js/codemirror/mode/erlang/index.html +1 -1
- data/templates/static/js/codemirror/mode/gfm/gfm.js +2 -1
- data/templates/static/js/codemirror/mode/gfm/index.html +1 -2
- data/templates/static/js/codemirror/mode/gfm/test.js +84 -225
- data/templates/static/js/codemirror/mode/go/index.html +1 -1
- data/templates/static/js/codemirror/mode/groovy/index.html +1 -1
- data/templates/static/js/codemirror/mode/haskell/index.html +1 -1
- data/templates/static/js/codemirror/mode/javascript/index.html +2 -2
- data/templates/static/js/codemirror/mode/javascript/javascript.js +13 -2
- data/templates/static/js/codemirror/mode/less/index.html +1 -1
- data/templates/static/js/codemirror/mode/lua/index.html +1 -1
- data/templates/static/js/codemirror/mode/markdown/index.html +1 -1
- data/templates/static/js/codemirror/mode/markdown/markdown.js +8 -7
- data/templates/static/js/codemirror/mode/markdown/test.js +579 -1266
- data/templates/static/js/codemirror/mode/meta.js +71 -0
- data/templates/static/js/codemirror/mode/mysql/index.html +2 -0
- data/templates/static/js/codemirror/mode/ocaml/index.html +1 -1
- data/templates/static/js/codemirror/mode/php/index.html +1 -1
- data/templates/static/js/codemirror/mode/plsql/index.html +2 -0
- data/templates/static/js/codemirror/mode/python/index.html +1 -1
- data/templates/static/js/codemirror/mode/ruby/index.html +1 -1
- data/templates/static/js/codemirror/mode/sass/index.html +54 -0
- data/templates/static/js/codemirror/mode/sass/sass.js +349 -0
- data/templates/static/js/codemirror/mode/shell/index.html +1 -1
- data/templates/static/js/codemirror/mode/sieve/LICENSE +0 -4
- data/templates/static/js/codemirror/mode/sieve/sieve.js +37 -10
- data/templates/static/js/codemirror/mode/smalltalk/index.html +1 -1
- data/templates/static/js/codemirror/mode/sparql/index.html +1 -1
- data/templates/static/js/codemirror/mode/sql/index.html +68 -0
- data/templates/static/js/codemirror/mode/sql/sql.js +268 -0
- data/templates/static/js/codemirror/mode/stex/test.js +104 -343
- data/templates/static/js/codemirror/mode/tiddlywiki/index.html +1 -1
- data/templates/static/js/codemirror/mode/vb/index.html +1 -1
- data/templates/static/js/codemirror/mode/xquery/test.js +54 -67
- data/templates/static/js/codemirror/mode/xquery/xquery.js +8 -8
- data/templates/static/js/crossfilter.min.js +1 -0
- data/templates/views/edit.slim +31 -0
- data/templates/views/footer.slim +1 -1
- data/templates/views/layout.slim +23 -5
- data/templates/views/navbar.slim +17 -16
- metadata +16 -30
- data/examples/examples01/static/css/codemirror.css +0 -1247
- data/examples/examples01/static/js/codemirror-compressed-3-0.js +0 -5
- data/examples/examples01/views/about.slim +0 -15
- data/examples/examples01/views/application.slim +0 -0
- data/examples/examples01/views/layout_cm.slim +0 -17
- data/templates/static/js/codemirror/lib/util/closetag.js +0 -85
- data/templates/static/js/codemirror/lib/util/colorize.js +0 -29
- data/templates/static/js/codemirror/lib/util/continuecomment.js +0 -36
- data/templates/static/js/codemirror/lib/util/continuelist.js +0 -28
- data/templates/static/js/codemirror/lib/util/dialog.css +0 -32
- data/templates/static/js/codemirror/lib/util/dialog.js +0 -75
- data/templates/static/js/codemirror/lib/util/foldcode.js +0 -182
- data/templates/static/js/codemirror/lib/util/formatting.js +0 -108
- data/templates/static/js/codemirror/lib/util/javascript-hint.js +0 -137
- data/templates/static/js/codemirror/lib/util/loadmode.js +0 -51
- data/templates/static/js/codemirror/lib/util/match-highlighter.js +0 -46
- data/templates/static/js/codemirror/lib/util/matchbrackets.js +0 -63
- data/templates/static/js/codemirror/lib/util/multiplex.js +0 -95
- data/templates/static/js/codemirror/lib/util/overlay.js +0 -59
- data/templates/static/js/codemirror/lib/util/pig-hint.js +0 -117
- data/templates/static/js/codemirror/lib/util/runmode-standalone.js +0 -90
- data/templates/static/js/codemirror/lib/util/runmode.js +0 -52
- data/templates/static/js/codemirror/lib/util/search.js +0 -119
- data/templates/static/js/codemirror/lib/util/searchcursor.js +0 -119
- data/templates/static/js/codemirror/lib/util/simple-hint.css +0 -16
- data/templates/static/js/codemirror/lib/util/simple-hint.js +0 -102
- data/templates/static/js/codemirror/lib/util/xml-hint.js +0 -131
- data/templates/views/about.slim +0 -15
data/Rakefile
CHANGED
@@ -1 +1,21 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
desc "Update the build date for the gem"
|
4
|
+
task :update_build_date do
|
5
|
+
version_file = File.join(".", "lib", "swagr", "version.rb")
|
6
|
+
lines = File.readlines(version_file)
|
7
|
+
lines = lines.map do |line|
|
8
|
+
if line =~ /(\s*)GemBuildDate = "(.+)"/
|
9
|
+
timestamp = Time.new.strftime "%Y-%m-%d %H:%M.%S"
|
10
|
+
"#{$1}GemBuildDate = #{timestamp.inspect}\n"
|
11
|
+
else
|
12
|
+
line
|
13
|
+
end
|
14
|
+
end
|
15
|
+
File.open(version_file, "w") {|fh| fh.write lines.join()}
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Update build date then build and install gem"
|
19
|
+
task :uinstall => [:update_build_date, :install] do
|
20
|
+
# Nothing to do! Work is done by the two other tasks...
|
21
|
+
end
|
data/bin/swagr
CHANGED
@@ -14,6 +14,15 @@ SkeletonTarball = File.join(SkeletonDir, DefaultSkeletonTarball)
|
|
14
14
|
StaticDir = PublicDir = "static"
|
15
15
|
DefaultSubdirs = ["coffee", "views", StaticDir]
|
16
16
|
|
17
|
+
def output_lines_from_running_command(command)
|
18
|
+
`#{command}`.split("\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
def first_output_line_matching(command, regexp)
|
22
|
+
lines = output_lines_from_running_command command
|
23
|
+
lines.each {|line| return line if line =~ regexp}
|
24
|
+
end
|
25
|
+
|
17
26
|
class SwagrCommand < Thor
|
18
27
|
|
19
28
|
include Thor::Actions
|
@@ -22,25 +31,44 @@ class SwagrCommand < Thor
|
|
22
31
|
SwagrSourceRoot
|
23
32
|
end
|
24
33
|
|
34
|
+
desc "version", "Print the current version of swagr"
|
35
|
+
def version
|
36
|
+
say "Swagr version #{Swagr::VERSION} built #{Swagr::GemBuildDate}"
|
37
|
+
end
|
38
|
+
|
25
39
|
desc "upgrade", "Upgrade used libs by re-downloading the latest versions of needed libs. Might brake some of your code so use with caution."
|
26
40
|
def upgrade
|
27
41
|
inside File.join(SwagrSourceRoot, "templates", PublicDir, "js") do
|
28
42
|
get "http://d3js.org/d3.v3.min.js"
|
29
43
|
get "http://coffeescript.org/extras/coffee-script.js"
|
30
44
|
get "http://code.jquery.com/jquery-latest.js"
|
45
|
+
get "https://raw.github.com/square/crossfilter/master/crossfilter.min.js"
|
31
46
|
|
32
|
-
# Now get the codemirror tarball
|
47
|
+
# Now get the codemirror tarball and unpack it
|
33
48
|
get "http://codemirror.net/codemirror.zip"
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
49
|
+
# Find the name of the dir were files will be unpacked by "unzip -l" and parsing the lines until matches regexp
|
50
|
+
re = /\s*0.+(codemirror-\d+.\d+.?\d*)\//
|
51
|
+
line = first_output_line_matching "unzip -l codemirror.zip", re
|
52
|
+
if line
|
53
|
+
line =~ re
|
54
|
+
codemirror_dir = $1
|
55
|
+
say "Found codemirror unzipped to #{codemirror_dir}"
|
56
|
+
|
57
|
+
run "unzip codemirror.zip"
|
58
|
+
|
59
|
+
# Now copy from unpacked codemirror dir to our template dir
|
60
|
+
FileUtils.rm_rf "codemirror" # Delete old dest dir so we get a fresh start
|
61
|
+
empty_directory "codemirror"
|
62
|
+
directory File.join(codemirror_dir, "lib"), "codemirror/lib"
|
63
|
+
directory File.join(codemirror_dir, "keymap"), "codemirror/keymap"
|
64
|
+
directory File.join(codemirror_dir, "mode"), "codemirror/mode"
|
65
|
+
directory File.join(codemirror_dir, "theme"), "codemirror/theme"
|
66
|
+
end
|
67
|
+
|
68
|
+
# Cleanup after codemirror download and unpack
|
41
69
|
FileUtils.rm_rf "codemirror.zip"
|
42
70
|
say "Removed tarball"
|
43
|
-
FileUtils.rm_rf
|
71
|
+
FileUtils.rm_rf codemirror_dir
|
44
72
|
say "Removed unpacked codemirror dir"
|
45
73
|
end
|
46
74
|
|
data/examples/examples01/app.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
h1 Let's try in-browser code editing
|
2
|
+
|
3
|
+
/! script src="js/coffee-script.js" type="text/javascript"
|
4
|
+
div class="container" id="code"
|
5
|
+
textarea id="editor" cols="50" rows="10" style="width:30%"
|
6
|
+
| # Hello
|
7
|
+
# This looks ok. How very nice!
|
8
|
+
a = 1 + 2
|
9
|
+
|
10
|
+
/! --------------------------------------------------------------
|
11
|
+
/! -- Include files needed by CodeMirror (CM)
|
12
|
+
/! --------------------------------------------------------------
|
13
|
+
link rel="stylesheet" href="js/codemirror/lib/codemirror.css"
|
14
|
+
script src="js/codemirror/lib/codemirror.js"
|
15
|
+
|
16
|
+
/! CM utils that you use:
|
17
|
+
script src="js/codemirror/lib/util/loadmode.js"
|
18
|
+
|
19
|
+
/! CM modes that you use:
|
20
|
+
script src="js/codemirror/mode/ruby/ruby.js"
|
21
|
+
|
22
|
+
/! CM themes that you use:
|
23
|
+
link rel="stylesheet" href="js/codemirror/theme/lesser-dark.css"
|
24
|
+
|
25
|
+
|
26
|
+
script type="text/javascript"
|
27
|
+
| var editor = CodeMirror.fromTextArea(document.getElementById("editor"), {
|
28
|
+
lineNumbers: true,
|
29
|
+
mode: "ruby",
|
30
|
+
theme: "lesser-dark"
|
31
|
+
});
|
@@ -1,2 +1,2 @@
|
|
1
|
-
h3 Footer...
|
1
|
+
/! h3 Footer...
|
2
2
|
| Copyright © #{year} #{copyright_holders}
|
@@ -2,20 +2,31 @@ doctype html
|
|
2
2
|
html
|
3
3
|
head
|
4
4
|
meta charset="utf-8"
|
5
|
-
|
5
|
+
|
6
6
|
meta name="viewport" content="width=device-width, initial-scale=1.0"
|
7
7
|
meta name="description" content=""
|
8
8
|
meta name="author" content="FIXME: YOUR NAME"
|
9
|
-
|
10
|
-
|
9
|
+
|
10
|
+
title Swagr web app template
|
11
|
+
|
12
|
+
/! --------------------------------------------------------------
|
13
|
+
/! -- Files needed by Bootstrap
|
14
|
+
/! --------------------------------------------------------------
|
15
|
+
link href="css/bootstrap.css" rel="stylesheet"
|
16
|
+
|
17
|
+
|
18
|
+
/! --------------------------------------------------------------
|
19
|
+
/! -- Our own style file + custom changes inline
|
20
|
+
/! --------------------------------------------------------------
|
11
21
|
link href="css/style.css" rel="stylesheet" /! media="screen"
|
12
22
|
style
|
13
23
|
| body {
|
14
24
|
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
|
15
25
|
}
|
26
|
+
|
16
27
|
body
|
17
28
|
|
18
|
-
div class="container"
|
29
|
+
div class="container" id="main_body_content"
|
19
30
|
== slim :navbar
|
20
31
|
== yield
|
21
32
|
|
@@ -24,4 +35,11 @@ html
|
|
24
35
|
== slim :footer
|
25
36
|
|
26
37
|
script src="js/jquery-latest.js"
|
27
|
-
script src="js/bootstrap.min.js"
|
38
|
+
script src="js/bootstrap.min.js"
|
39
|
+
|
40
|
+
/! Ensure the active class on the main navbar is updated if one of the nav links is clicked
|
41
|
+
script type="text/javascript"
|
42
|
+
| $('#top-navbar-ul li a').on('click', function() {
|
43
|
+
$(this).parent().parent().find('.active').removeClass('active');
|
44
|
+
$(this).parent().addClass('active').css('font-weight', 'bold');
|
45
|
+
});
|
@@ -1,16 +1,17 @@
|
|
1
|
-
div
|
2
|
-
div class="navbar-
|
3
|
-
div class="
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
1
|
+
div id="#top-navbar"
|
2
|
+
div class="navbar navbar-inverse navbar-fixed-top"
|
3
|
+
div class="navbar-inner"
|
4
|
+
div class="container"
|
5
|
+
a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"
|
6
|
+
span class="icon-bar"
|
7
|
+
span class="icon-bar"
|
8
|
+
span class="icon-bar"
|
9
|
+
a class="brand" href="/" SwagrApp
|
10
|
+
div class="nav-collapse collapse"
|
11
|
+
ul class="nav" id="top-navbar-"
|
12
|
+
li class="active"
|
13
|
+
a href="/" Home
|
14
|
+
li
|
15
|
+
a href="/edit" Edit
|
16
|
+
li
|
17
|
+
a href="/about" About
|
data/lib/swagr/version.rb
CHANGED
data/templates/app.rb
CHANGED
@@ -115,6 +115,10 @@
|
|
115
115
|
motion: 'moveByWords',
|
116
116
|
motionArgs: { forward: false, wordEnd: true, bigWord: true,
|
117
117
|
inclusive: true }},
|
118
|
+
{ keys: ['{'], type: 'motion', motion: 'moveByParagraph',
|
119
|
+
motionArgs: { forward: false }},
|
120
|
+
{ keys: ['}'], type: 'motion', motion: 'moveByParagraph',
|
121
|
+
motionArgs: { forward: true }},
|
118
122
|
{ keys: ['Ctrl-f'], type: 'motion',
|
119
123
|
motion: 'moveByPage', motionArgs: { forward: true }},
|
120
124
|
{ keys: ['Ctrl-b'], type: 'motion',
|
@@ -247,7 +251,7 @@
|
|
247
251
|
var specialKeys = ['Left', 'Right', 'Up', 'Down', 'Space', 'Backspace',
|
248
252
|
'Esc', 'Home', 'End', 'PageUp', 'PageDown'];
|
249
253
|
var validMarks = upperCaseAlphabet.concat(lowerCaseAlphabet).concat(
|
250
|
-
numbers);
|
254
|
+
numbers).concat(['<', '>']);
|
251
255
|
var validRegisters = upperCaseAlphabet.concat(lowerCaseAlphabet).concat(
|
252
256
|
numbers).concat('-\"'.split(''));
|
253
257
|
|
@@ -720,7 +724,11 @@
|
|
720
724
|
// Handle user defined Ex to Ex mappings
|
721
725
|
exCommandDispatcher.processCommand(cm, command.exArgs.input);
|
722
726
|
} else {
|
723
|
-
|
727
|
+
if (vim.visualMode) {
|
728
|
+
showPrompt(cm, onPromptClose, ':', undefined, '\'<,\'>');
|
729
|
+
} else {
|
730
|
+
showPrompt(cm, onPromptClose, ':');
|
731
|
+
}
|
724
732
|
}
|
725
733
|
},
|
726
734
|
evalInput: function(cm, vim) {
|
@@ -806,6 +814,12 @@
|
|
806
814
|
// CodeMirror can't figure out that we changed directions...
|
807
815
|
cm.setCursor(selectionStart);
|
808
816
|
cm.setSelection(selectionStart, selectionEnd);
|
817
|
+
updateMark(cm, vim, '<',
|
818
|
+
cursorIsBefore(selectionStart, selectionEnd) ? selectionStart
|
819
|
+
: selectionEnd);
|
820
|
+
updateMark(cm, vim, '>',
|
821
|
+
cursorIsBefore(selectionStart, selectionEnd) ? selectionEnd
|
822
|
+
: selectionStart);
|
809
823
|
} else if (!operator) {
|
810
824
|
curEnd = clipCursorToContent(cm, curEnd);
|
811
825
|
cm.setCursor(curEnd.line, curEnd.ch);
|
@@ -923,6 +937,22 @@
|
|
923
937
|
cm.setCursor(curStart);
|
924
938
|
return curEnd;
|
925
939
|
},
|
940
|
+
moveByParagraph: function(cm, motionArgs) {
|
941
|
+
var line = cm.getCursor().line;
|
942
|
+
var repeat = motionArgs.repeat;
|
943
|
+
var inc = motionArgs.forward ? 1 : -1;
|
944
|
+
for (var i = 0; i < repeat; i++) {
|
945
|
+
if ((!motionArgs.forward && line === 0) ||
|
946
|
+
(motionArgs.forward && line == cm.lineCount() - 1)) {
|
947
|
+
break;
|
948
|
+
}
|
949
|
+
line += inc;
|
950
|
+
while (line !== 0 && line != cm.lineCount - 1 && cm.getLine(line)) {
|
951
|
+
line += inc;
|
952
|
+
}
|
953
|
+
}
|
954
|
+
return { line: line, ch: 0 };
|
955
|
+
},
|
926
956
|
moveByWords: function(cm, motionArgs) {
|
927
957
|
return moveToWord(cm, motionArgs.repeat, !!motionArgs.forward,
|
928
958
|
!!motionArgs.wordEnd, !!motionArgs.bigWord);
|
@@ -1119,21 +1149,29 @@
|
|
1119
1149
|
cm.setSelection(curStart, curEnd);
|
1120
1150
|
}
|
1121
1151
|
} else {
|
1152
|
+
curStart = cm.getCursor('anchor');
|
1153
|
+
curEnd = cm.getCursor('head');
|
1122
1154
|
if (!vim.visualLine && actionArgs.linewise) {
|
1123
1155
|
// Shift-V pressed in characterwise visual mode. Switch to linewise
|
1124
1156
|
// visual mode instead of exiting visual mode.
|
1125
1157
|
vim.visualLine = true;
|
1126
|
-
curStart = cm.getCursor('anchor');
|
1127
|
-
curEnd = cm.getCursor('head');
|
1128
1158
|
curStart.ch = cursorIsBefore(curStart, curEnd) ? 0 :
|
1129
1159
|
lineLength(cm, curStart.line);
|
1130
1160
|
curEnd.ch = cursorIsBefore(curStart, curEnd) ?
|
1131
1161
|
lineLength(cm, curEnd.line) : 0;
|
1132
1162
|
cm.setSelection(curStart, curEnd);
|
1163
|
+
} else if (vim.visualLine && !actionArgs.linewise) {
|
1164
|
+
// v pressed in linewise visual mode. Switch to characterwise visual
|
1165
|
+
// mode instead of exiting visual mode.
|
1166
|
+
vim.visualLine = false;
|
1133
1167
|
} else {
|
1134
1168
|
exitVisualMode(cm, vim);
|
1135
1169
|
}
|
1136
1170
|
}
|
1171
|
+
updateMark(cm, vim, '<', cursorIsBefore(curStart, curEnd) ? curStart
|
1172
|
+
: curEnd);
|
1173
|
+
updateMark(cm, vim, '>', cursorIsBefore(curStart, curEnd) ? curEnd
|
1174
|
+
: curStart);
|
1137
1175
|
},
|
1138
1176
|
joinLines: function(cm, actionArgs, vim) {
|
1139
1177
|
var curStart, curEnd;
|
@@ -1232,13 +1270,7 @@
|
|
1232
1270
|
},
|
1233
1271
|
setMark: function(cm, actionArgs, vim) {
|
1234
1272
|
var markName = actionArgs.selectedCharacter;
|
1235
|
-
|
1236
|
-
return;
|
1237
|
-
}
|
1238
|
-
if (vim.marks[markName]) {
|
1239
|
-
vim.marks[markName].clear();
|
1240
|
-
}
|
1241
|
-
vim.marks[markName] = cm.setBookmark(cm.getCursor());
|
1273
|
+
updateMark(cm, vim, markName, cm.getCursor());
|
1242
1274
|
},
|
1243
1275
|
replace: function(cm, actionArgs) {
|
1244
1276
|
var replaceWith = actionArgs.selectedCharacter;
|
@@ -1636,6 +1668,16 @@
|
|
1636
1668
|
return clipCursorToContent(cm, { line: line, ch: repeat - 1 });
|
1637
1669
|
}
|
1638
1670
|
|
1671
|
+
function updateMark(cm, vim, markName, pos) {
|
1672
|
+
if (!inArray(markName, validMarks)) {
|
1673
|
+
return;
|
1674
|
+
}
|
1675
|
+
if (vim.marks[markName]) {
|
1676
|
+
vim.marks[markName].clear();
|
1677
|
+
}
|
1678
|
+
vim.marks[markName] = cm.setBookmark(pos);
|
1679
|
+
}
|
1680
|
+
|
1639
1681
|
function charIdxInLine(start, line, character, forward, includeChar) {
|
1640
1682
|
// Search for char in line.
|
1641
1683
|
// motion_options: {forward, includeChar}
|
@@ -1804,6 +1846,12 @@
|
|
1804
1846
|
setMarked: function(marked) {
|
1805
1847
|
this.marked = marked;
|
1806
1848
|
},
|
1849
|
+
getOverlay: function() {
|
1850
|
+
return this.searchOverlay;
|
1851
|
+
},
|
1852
|
+
setOverlay: function(overlay) {
|
1853
|
+
this.searchOverlay = overlay;
|
1854
|
+
},
|
1807
1855
|
isReversed: function() {
|
1808
1856
|
return getVimGlobalState().isReversed;
|
1809
1857
|
},
|
@@ -1815,9 +1863,9 @@
|
|
1815
1863
|
var vim = getVimState(cm);
|
1816
1864
|
return vim.searchState_ || (vim.searchState_ = new SearchState());
|
1817
1865
|
}
|
1818
|
-
function dialog(cm, text, shortText, callback) {
|
1866
|
+
function dialog(cm, text, shortText, callback, initialValue) {
|
1819
1867
|
if (cm.openDialog) {
|
1820
|
-
cm.openDialog(text, callback, {bottom: true});
|
1868
|
+
cm.openDialog(text, callback, { bottom: true, value: initialValue });
|
1821
1869
|
}
|
1822
1870
|
else {
|
1823
1871
|
callback(prompt(shortText, ""));
|
@@ -1899,9 +1947,10 @@
|
|
1899
1947
|
return raw;
|
1900
1948
|
}
|
1901
1949
|
var searchPromptDesc = '(Javascript regexp)';
|
1902
|
-
function showPrompt(cm, onPromptClose, prefix, desc) {
|
1950
|
+
function showPrompt(cm, onPromptClose, prefix, desc, initialValue) {
|
1903
1951
|
var shortText = (prefix || '') + ' ' + (desc || '');
|
1904
|
-
dialog(cm, makePrompt(prefix, desc), shortText, onPromptClose
|
1952
|
+
dialog(cm, makePrompt(prefix, desc), shortText, onPromptClose,
|
1953
|
+
initialValue);
|
1905
1954
|
}
|
1906
1955
|
function regexEqual(r1, r2) {
|
1907
1956
|
if (r1 instanceof RegExp && r2 instanceof RegExp) {
|
@@ -1934,17 +1983,53 @@
|
|
1934
1983
|
state.setQuery(query);
|
1935
1984
|
});
|
1936
1985
|
}
|
1986
|
+
function searchOverlay(query) {
|
1987
|
+
return {
|
1988
|
+
token: function(stream) {
|
1989
|
+
var match = stream.match(query, false);
|
1990
|
+
if (match) {
|
1991
|
+
if (!stream.sol()) {
|
1992
|
+
// Backtrack 1 to match \b
|
1993
|
+
stream.backUp(1);
|
1994
|
+
if (!query.exec(stream.next() + match[0])) {
|
1995
|
+
stream.next();
|
1996
|
+
return null;
|
1997
|
+
}
|
1998
|
+
}
|
1999
|
+
stream.match(query);
|
2000
|
+
return "searching";
|
2001
|
+
}
|
2002
|
+
while (!stream.eol()) {
|
2003
|
+
stream.next();
|
2004
|
+
if (stream.match(query, false)) break;
|
2005
|
+
}
|
2006
|
+
},
|
2007
|
+
query: query
|
2008
|
+
};
|
2009
|
+
}
|
1937
2010
|
function highlightSearchMatches(cm, query) {
|
1938
|
-
|
1939
|
-
|
1940
|
-
|
1941
|
-
|
1942
|
-
|
1943
|
-
|
1944
|
-
|
1945
|
-
|
2011
|
+
if (cm.addOverlay) {
|
2012
|
+
var overlay = getSearchState(cm).getOverlay();
|
2013
|
+
if (!overlay || query != overlay.query) {
|
2014
|
+
if (overlay) {
|
2015
|
+
cm.removeOverlay(overlay);
|
2016
|
+
}
|
2017
|
+
overlay = searchOverlay(query);
|
2018
|
+
cm.addOverlay(overlay);
|
2019
|
+
getSearchState(cm).setOverlay(overlay);
|
2020
|
+
}
|
2021
|
+
} else {
|
2022
|
+
// TODO: Highlight only text inside the viewport. Highlighting everything
|
2023
|
+
// is inefficient and expensive.
|
2024
|
+
if (cm.lineCount() < 2000) { // This is too expensive on big documents.
|
2025
|
+
var marked = [];
|
2026
|
+
for (var cursor = cm.getSearchCursor(query);
|
2027
|
+
cursor.findNext();) {
|
2028
|
+
marked.push(cm.markText(cursor.from(), cursor.to(),
|
2029
|
+
{ className: 'cm-searching' }));
|
2030
|
+
}
|
2031
|
+
getSearchState(cm).setMarked(marked);
|
1946
2032
|
}
|
1947
|
-
getSearchState(cm).setMarked(marked);
|
1948
2033
|
}
|
1949
2034
|
}
|
1950
2035
|
function findNext(cm, prev, repeat) {
|
@@ -1978,20 +2063,52 @@
|
|
1978
2063
|
return cursor.from();
|
1979
2064
|
});}
|
1980
2065
|
function clearSearchHighlight(cm) {
|
1981
|
-
cm.
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
1991
|
-
marked
|
2066
|
+
if (cm.addOverlay) {
|
2067
|
+
cm.removeOverlay(getSearchState(cm).getOverlay());
|
2068
|
+
getSearchState(cm).setOverlay(null);
|
2069
|
+
} else {
|
2070
|
+
cm.operation(function() {
|
2071
|
+
var state = getSearchState(cm);
|
2072
|
+
if (!state.getQuery()) {
|
2073
|
+
return;
|
2074
|
+
}
|
2075
|
+
var marked = state.getMarked();
|
2076
|
+
if (!marked) {
|
2077
|
+
return;
|
2078
|
+
}
|
2079
|
+
for (var i = 0; i < marked.length; ++i) {
|
2080
|
+
marked[i].clear();
|
2081
|
+
}
|
2082
|
+
state.setMarked(null);
|
2083
|
+
});
|
2084
|
+
}
|
2085
|
+
}
|
2086
|
+
/**
|
2087
|
+
* Check if pos is in the specified range, INCLUSIVE.
|
2088
|
+
* Range can be specified with 1 or 2 arguments.
|
2089
|
+
* If the first range argument is an array, treat it as an array of line
|
2090
|
+
* numbers. Match pos against any of the lines.
|
2091
|
+
* If the first range argument is a number,
|
2092
|
+
* if there is only 1 range argument, check if pos has the same line
|
2093
|
+
* number
|
2094
|
+
* if there are 2 range arguments, then check if pos is in between the two
|
2095
|
+
* range arguments.
|
2096
|
+
*/
|
2097
|
+
function isInRange(pos, start, end) {
|
2098
|
+
if (typeof pos != 'number') {
|
2099
|
+
// Assume it is a cursor position. Get the line number.
|
2100
|
+
pos = pos.line;
|
2101
|
+
}
|
2102
|
+
if (start instanceof Array) {
|
2103
|
+
return inArray(pos, start);
|
2104
|
+
} else {
|
2105
|
+
if (end) {
|
2106
|
+
return (pos >= start && pos <= end);
|
2107
|
+
} else {
|
2108
|
+
return pos == start;
|
1992
2109
|
}
|
1993
|
-
|
1994
|
-
|
2110
|
+
}
|
2111
|
+
}
|
1995
2112
|
|
1996
2113
|
// Ex command handling
|
1997
2114
|
// Care must be taken when adding to the default Ex command map. For any
|
@@ -2001,14 +2118,23 @@
|
|
2001
2118
|
{ name: 'map', type: 'builtIn' },
|
2002
2119
|
{ name: 'write', shortName: 'w', type: 'builtIn' },
|
2003
2120
|
{ name: 'undo', shortName: 'u', type: 'builtIn' },
|
2004
|
-
{ name: 'redo', shortName: 'red', type: 'builtIn' }
|
2121
|
+
{ name: 'redo', shortName: 'red', type: 'builtIn' },
|
2122
|
+
{ name: 'substitute', shortName: 's', type: 'builtIn'}
|
2005
2123
|
];
|
2006
|
-
|
2124
|
+
Vim.ExCommandDispatcher = function() {
|
2007
2125
|
this.buildCommandMap_();
|
2008
2126
|
};
|
2009
|
-
ExCommandDispatcher.prototype = {
|
2127
|
+
Vim.ExCommandDispatcher.prototype = {
|
2010
2128
|
processCommand: function(cm, input) {
|
2011
|
-
var
|
2129
|
+
var inputStream = new CodeMirror.StringStream(input);
|
2130
|
+
var params = {};
|
2131
|
+
params.input = input;
|
2132
|
+
try {
|
2133
|
+
this.parseInput_(cm, inputStream, params);
|
2134
|
+
} catch(e) {
|
2135
|
+
showConfirm(cm, e);
|
2136
|
+
return;
|
2137
|
+
}
|
2012
2138
|
var commandName;
|
2013
2139
|
if (!params.commandName) {
|
2014
2140
|
// If only a line range is defined, move to the line.
|
@@ -2019,6 +2145,7 @@
|
|
2019
2145
|
var command = this.matchCommand_(params.commandName);
|
2020
2146
|
if (command) {
|
2021
2147
|
commandName = command.name;
|
2148
|
+
this.parseCommandArgs_(inputStream, params, command);
|
2022
2149
|
if (command.type == 'exToKey') {
|
2023
2150
|
// Handle Ex to Key mapping.
|
2024
2151
|
for (var i = 0; i < command.toKeys.length; i++) {
|
@@ -2038,37 +2165,63 @@
|
|
2038
2165
|
}
|
2039
2166
|
exCommands[commandName](cm, params);
|
2040
2167
|
},
|
2041
|
-
parseInput_: function(
|
2042
|
-
|
2043
|
-
result.input = input;
|
2044
|
-
var idx = 0;
|
2045
|
-
// Trim preceding ':'.
|
2046
|
-
var colons = (/^:+/).exec(input);
|
2047
|
-
if (colons) {
|
2048
|
-
idx += colons[0].length;
|
2049
|
-
}
|
2050
|
-
|
2168
|
+
parseInput_: function(cm, inputStream, result) {
|
2169
|
+
inputStream.eatWhile(':');
|
2051
2170
|
// Parse range.
|
2052
|
-
|
2053
|
-
|
2054
|
-
result.
|
2055
|
-
|
2171
|
+
if (inputStream.eat('%')) {
|
2172
|
+
result.line = 0;
|
2173
|
+
result.lineEnd = cm.lineCount() - 1;
|
2174
|
+
} else {
|
2175
|
+
result.line = this.parseLineSpec_(cm, inputStream);
|
2176
|
+
if (result.line !== undefined && inputStream.eat(',')) {
|
2177
|
+
result.lineEnd = this.parseLineSpec_(cm, inputStream);
|
2178
|
+
}
|
2056
2179
|
}
|
2057
2180
|
|
2058
2181
|
// Parse command name.
|
2059
|
-
var commandMatch = (/^(\w+)/)
|
2182
|
+
var commandMatch = inputStream.match(/^(\w+)/);
|
2060
2183
|
if (commandMatch) {
|
2061
2184
|
result.commandName = commandMatch[1];
|
2062
|
-
|
2185
|
+
} else {
|
2186
|
+
result.commandName = inputStream.match(/.*/)[0];
|
2063
2187
|
}
|
2064
2188
|
|
2189
|
+
return result;
|
2190
|
+
},
|
2191
|
+
parseLineSpec_: function(cm, inputStream) {
|
2192
|
+
var numberMatch = inputStream.match(/^(\d+)/);
|
2193
|
+
if (numberMatch) {
|
2194
|
+
return parseInt(numberMatch[1], 10) - 1;
|
2195
|
+
}
|
2196
|
+
switch (inputStream.next()) {
|
2197
|
+
case '.':
|
2198
|
+
return cm.getCursor().line;
|
2199
|
+
case '$':
|
2200
|
+
return cm.lineCount() - 1;
|
2201
|
+
case '\'':
|
2202
|
+
var mark = getVimState(cm).marks[inputStream.next()];
|
2203
|
+
if (mark && mark.find()) {
|
2204
|
+
return mark.find().line;
|
2205
|
+
} else {
|
2206
|
+
throw "Mark not set";
|
2207
|
+
}
|
2208
|
+
break;
|
2209
|
+
default:
|
2210
|
+
inputStream.backUp(1);
|
2211
|
+
return cm.getCursor().line;
|
2212
|
+
}
|
2213
|
+
},
|
2214
|
+
parseCommandArgs_: function(inputStream, params, command) {
|
2215
|
+
if (inputStream.eol()) {
|
2216
|
+
return;
|
2217
|
+
}
|
2218
|
+
params.argString = inputStream.match(/.*/)[0];
|
2065
2219
|
// Parse command-line arguments
|
2066
|
-
var
|
2220
|
+
var delim = command.argDelimiter || /\s+/;
|
2221
|
+
var args = trim(params.argString).split(delim);
|
2067
2222
|
if (args.length && args[0]) {
|
2068
|
-
|
2223
|
+
params.args = args;
|
2069
2224
|
}
|
2070
|
-
|
2071
|
-
return result;
|
2072
2225
|
},
|
2073
2226
|
matchCommand_: function(commandName) {
|
2074
2227
|
// Return the command in the command map that matches the shortest
|
@@ -2095,9 +2248,9 @@
|
|
2095
2248
|
}
|
2096
2249
|
},
|
2097
2250
|
map: function(lhs, rhs) {
|
2098
|
-
if (lhs.charAt(0) == ':') {
|
2251
|
+
if (lhs != ':' && lhs.charAt(0) == ':') {
|
2099
2252
|
var commandName = lhs.substring(1);
|
2100
|
-
if (rhs.charAt(0) == ':') {
|
2253
|
+
if (rhs != ':' && rhs.charAt(0) == ':') {
|
2101
2254
|
// Ex to Ex mapping
|
2102
2255
|
this.commandMap_[commandName] = {
|
2103
2256
|
name: commandName,
|
@@ -2113,7 +2266,7 @@
|
|
2113
2266
|
};
|
2114
2267
|
}
|
2115
2268
|
} else {
|
2116
|
-
if (rhs.charAt(0) == ':') {
|
2269
|
+
if (rhs != ':' && rhs.charAt(0) == ':') {
|
2117
2270
|
// Key to Ex mapping.
|
2118
2271
|
defaultKeymap.unshift({
|
2119
2272
|
keys: parseKeyString(lhs),
|
@@ -2172,7 +2325,7 @@
|
|
2172
2325
|
|
2173
2326
|
var exCommands = {
|
2174
2327
|
map: function(cm, params) {
|
2175
|
-
var mapArgs = params.
|
2328
|
+
var mapArgs = params.args;
|
2176
2329
|
if (!mapArgs || mapArgs.length < 2) {
|
2177
2330
|
if (cm) {
|
2178
2331
|
showConfirm(cm, 'Invalid mapping: ' + params.input);
|
@@ -2187,6 +2340,66 @@
|
|
2187
2340
|
motionArgs: { forward: false, explicitRepeat: true,
|
2188
2341
|
linewise: true, repeat: params.line }});
|
2189
2342
|
},
|
2343
|
+
substitute: function(cm, params) {
|
2344
|
+
var argString = params.argString;
|
2345
|
+
var slashes = findUnescapedSlashes(argString);
|
2346
|
+
if (slashes[0] !== 0) {
|
2347
|
+
showConfirm(cm, 'Substitutions should be of the form ' +
|
2348
|
+
':s/pattern/replace/');
|
2349
|
+
return;
|
2350
|
+
}
|
2351
|
+
var regexPart = argString.substring(slashes[0] + 1, slashes[1]);
|
2352
|
+
var replacePart = '';
|
2353
|
+
var flagsPart;
|
2354
|
+
var count;
|
2355
|
+
if (slashes[1]) {
|
2356
|
+
replacePart = argString.substring(slashes[1] + 1, slashes[2]);
|
2357
|
+
}
|
2358
|
+
if (slashes[2]) {
|
2359
|
+
// After the 3rd slash, we can have flags followed by a space followed
|
2360
|
+
// by count.
|
2361
|
+
var trailing = argString.substring(slashes[2] + 1).split(' ');
|
2362
|
+
flagsPart = trailing[0];
|
2363
|
+
count = parseInt(trailing[1]);
|
2364
|
+
}
|
2365
|
+
if (flagsPart) {
|
2366
|
+
regexPart = regexPart + '/' + flagsPart;
|
2367
|
+
}
|
2368
|
+
if (regexPart) {
|
2369
|
+
// If regex part is empty, then use the previous query. Otherwise use
|
2370
|
+
// the regex part as the new query.
|
2371
|
+
updateSearchQuery(cm, regexPart, true /** ignoreCase */,
|
2372
|
+
true /** smartCase */);
|
2373
|
+
}
|
2374
|
+
var state = getSearchState(cm);
|
2375
|
+
var query = state.getQuery();
|
2376
|
+
var lineStart = params.line || 0;
|
2377
|
+
var lineEnd = params.lineEnd || lineStart;
|
2378
|
+
if (count) {
|
2379
|
+
lineStart = lineEnd;
|
2380
|
+
lineEnd = lineStart + count - 1;
|
2381
|
+
}
|
2382
|
+
var startPos = clipCursorToContent(cm, { line: lineStart, ch: 0 });
|
2383
|
+
function doReplace() {
|
2384
|
+
for (var cursor = cm.getSearchCursor(query, startPos);
|
2385
|
+
cursor.findNext() &&
|
2386
|
+
isInRange(cursor.from(), lineStart, lineEnd);) {
|
2387
|
+
var text = cm.getRange(cursor.from(), cursor.to());
|
2388
|
+
var newText = text.replace(query, replacePart);
|
2389
|
+
cursor.replace(newText);
|
2390
|
+
}
|
2391
|
+
var vim = getVimState(cm);
|
2392
|
+
if (vim.visualMode) {
|
2393
|
+
exitVisualMode(cm, vim);
|
2394
|
+
}
|
2395
|
+
}
|
2396
|
+
if (cm.compoundChange) {
|
2397
|
+
// Only exists in v2
|
2398
|
+
cm.compoundChange(doReplace);
|
2399
|
+
} else {
|
2400
|
+
cm.operation(doReplace);
|
2401
|
+
}
|
2402
|
+
},
|
2190
2403
|
redo: CodeMirror.commands.redo,
|
2191
2404
|
undo: CodeMirror.commands.undo,
|
2192
2405
|
write: function(cm) {
|
@@ -2200,7 +2413,7 @@
|
|
2200
2413
|
}
|
2201
2414
|
};
|
2202
2415
|
|
2203
|
-
var exCommandDispatcher = new ExCommandDispatcher();
|
2416
|
+
var exCommandDispatcher = new Vim.ExCommandDispatcher();
|
2204
2417
|
|
2205
2418
|
// Register Vim with CodeMirror
|
2206
2419
|
function buildVimKeyMap() {
|