Compare commits

...
Sign in to create a new pull request.

227 commits

Author SHA1 Message Date
Joey Payne
ca8da0a3f3 Merge remote-tracking branch 'upstream/master' 2015-06-04 14:23:14 -06:00
Lennart Kats
f10da4cdb0 Merge pull request #2523 from ajaxorg/fix/various
Fix several small issues
2015-06-01 17:59:08 +02:00
Lennart Kats
d953740339 Merge pull request #2507 from ajaxorg/c9
Sync with cloud9
2015-06-01 17:39:25 +02:00
nightwing
6cec0b28b2 improve tmlanguage importer 2015-06-01 13:50:32 +04:00
nightwing
3f31ca57ed fix typo 2015-06-01 01:06:39 +04:00
Joey Payne
fb7144b622 Merge remote-tracking branch 'upstream/master' 2015-05-31 11:49:42 -06:00
nightwing
2249d06337 fix #2484 Hard-coded characterWidth in static_highlight.js
and remove dependence on mockdom
2015-05-31 17:42:00 +04:00
nightwing
1514d5f374 fix #2483 Exception on ctrl-alt-shift-click when $enableJumpToDef is true 2015-05-31 17:42:00 +04:00
nightwing
446e3e1bf9 fix #2522 Popup position is off when gutter isn't shown 2015-05-31 17:42:00 +04:00
Harutyun Amirjanyan
652dd7009c Merge pull request #2516 from ajaxorg/fix/highlighter
fix highlighting of tables in Gherkin  mode
2015-05-31 16:45:58 +04:00
Harutyun Amirjanyan
3d23e1e98f Merge pull request #2518 from ajaxorg/autocompleter
fix autocomplete blur handler
2015-05-31 16:45:36 +04:00
Harutyun Amirjanyan
cafc7e7ce1 Merge pull request #2521 from puffnfresh/patch-1
Fix invalid syntax in autoresize.html
2015-05-31 16:45:13 +04:00
Brian McKenna
abdc4c7510 Fix invalid syntax in autoresize.html
The options literal had a duplicate key.
2015-05-29 09:55:02 -06:00
nightwing
8c1d0ab7cf fix autocomplete blur handler 2015-05-28 13:56:33 +04:00
nightwing
9f57989043 fix highlighting of tables in Gherkin mode 2015-05-28 13:40:56 +04:00
nightwing
2a089863e2 fix highlighting of line-height:1.5 in less mode 2015-05-22 22:14:29 +04:00
nightwing
386c508042 convert paste into command 2015-05-22 22:14:15 +04:00
nightwing
dc7643db8d better invisible tabs (fixes #2109) 2015-05-22 21:57:13 +04:00
nightwing
5705a7c2c1 fix toggle comments in handlebars mode 2015-05-22 02:34:43 +04:00
nightwing
2e2d9bcdc9 add more php extensions 2015-05-22 02:34:43 +04:00
nightwing
a799a4086f fix quote pairing for "\n" 2015-05-22 02:34:43 +04:00
nightwing
af5c7a9c3b improve require support in worker 2015-05-22 02:34:30 +04:00
nightwing
fe96eef206 fix require for paths ending with .js in the worker 2015-05-21 23:01:27 +04:00
Lennart Kats
0a3b002e28 Merge pull request #1819 from ajaxorg/v-1.2
Refactor document delta handling for v1.2
2015-05-21 11:15:29 +02:00
nightwing
60439d927f update changelog 2015-05-21 13:01:17 +04:00
Lennart Kats
95bb17d04b Merge pull request #2496 from ajaxorg/fix/renderer
fix renderer issues with autosize
2015-05-21 10:57:04 +02:00
Lennart Kats
2c1b565591 Merge pull request #2500 from ajaxorg/fix/tokenizer
fix highlighting stopping randomly in the middle of the file
2015-05-21 10:53:05 +02:00
Harutyun Amirjanyan
53ea1a8665 Merge pull request #2502 from Pike/patch-1
Add array-of-tables to keygroup markup for toml files.
2015-05-20 22:30:19 +04:00
Axel Hecht
9534e4ea92 Add array-of-tables to keygroup markup
The markup for array-of-tables at https://github.com/toml-lang/toml#array-of-tables is
[[ foo ]]

Right now, the last ] isn't part of the markup. Figured making this an explicit token is the most apparent way to fix this.
2015-05-20 14:53:02 +02:00
nightwing
fa86327b3d fix highlighting stopping randomly in the middle of the file 2015-05-19 17:43:10 +04:00
Joey Payne
a68e8bea01 Merging latest commits.
Merge remote-tracking branch 'upstream/master'
2015-05-16 16:02:51 -06:00
nightwing
88d8cf3447 fix renderer test 2015-05-15 02:48:12 +04:00
nightwing
9e9aa8f328 use scroller as mousetarget to not miss mouse events on scrollmargin 2015-05-15 02:44:24 +04:00
nightwing
93c39ca5b0 handle hscrollbar change during autoresize 2015-05-15 02:43:41 +04:00
nightwing
0db985a3d7 fix #2495 editor freezes when setting scrollmargin and maxLines together 2015-05-15 01:53:19 +04:00
Ruben Daniels
ad5802be06 Merge pull request #2488 from ajaxorg/rounded-corners
Add rounded corners for selections
2015-05-10 19:07:21 -07:00
nightwing
0abd9ec30e rounded corners for selections 2015-05-10 14:01:28 +04:00
Harutyun Amirjanyan
6d205a8f7e Merge pull request #2470 from ajaxorg/fix/leak
Fix memory leak
2015-05-07 01:28:22 +04:00
Harutyun Amirjanyan
d2dc26f5a5 Merge pull request #2479 from bcjordan/patch-4
Update comment, add missing semicolon [ci skip]
2015-05-07 01:27:42 +04:00
Brian Jordan
ef4537a099 Update edit_session.js
Fix extra `the`
2015-05-05 09:07:46 -07:00
Harutyun Amirjanyan
46f76b4b06 Merge pull request #2473 from Leushenko/master
Add indentation for Scheme
2015-05-05 16:31:02 +04:00
Harutyun Amirjanyan
71d1ca9d20 Merge pull request #2476 from bcjordan/patch-2
Remove unused variable `EditSession`
2015-05-05 16:26:41 +04:00
Harutyun Amirjanyan
263a45db02 Merge pull request #2477 from bcjordan/patch-3
Remove unused parameter `mutateData` & add ;s
2015-05-05 16:26:28 +04:00
Joey Payne
9323a2616b Added support for nim programming language. 2015-05-04 22:54:09 -06:00
Brian Jordan
ad22b71cfe Update comment, add missing semicolon [ci skip] 2015-05-01 10:56:08 -07:00
Brian Jordan
cd8099b0ad Remove unused parameter mutateData & add ;s 2015-04-30 17:38:19 -07:00
Brian Jordan
a61d304cbb Remove unused variable EditSession 2015-04-30 17:14:16 -07:00
Alex Gilding
e72f1d8337 Add indentation for Scheme
Just copied over the Clojure indentation rules to Scheme and changed
the keywords to suit the language, so that Scheme programs can be
automatically indented too
2015-04-28 20:24:13 +01:00
nightwing
d080fe51d4 fix #2468 error in strict mode 2015-04-28 19:01:24 +04:00
Harutyun Amirjanyan
32cb8c6b0e Merge pull request #2472 from ph1ll/master
Expose ClipboardEvent in editor paste event
2015-04-28 00:51:58 +04:00
Phill Campbell
3ce8d76c89 Expose ClipboardEvent in editor paste event 2015-04-27 18:49:12 +01:00
nightwing
a842dcdee3 do not retain ref to the first editor (fixes #2469) 2015-04-26 14:44:47 +04:00
Ruben Daniels
0dcb1281cd Merge pull request #2459 from ajaxorg/c9
Sync with c9
2015-04-25 12:30:37 -07:00
Harutyun Amirjanyan
65ad04082f Merge pull request #2460 from sevin7676/master
SQL Server typos and keyword completion modifier
2015-04-23 18:11:41 +04:00
Lennart Kats
b6f7e5d6a1 Merge pull request #2461 from ajaxorg/highlighter
Fix highlighter issues
2015-04-23 07:38:28 +02:00
sevin7676
5a3bf2570f no keyword if in brackets 2015-04-22 06:06:52 -04:00
sevin7676
2d7ebc34b6 no keyword if in brackets 2015-04-22 06:05:54 -04:00
sevin7676
87044e8816 forgot keyword completions 2015-04-22 05:38:01 -04:00
sevin7676
82453d884b better completions, no unneeded string rule 2015-04-22 05:28:31 -04:00
nightwing
636ace5178 fix typo 2015-04-22 13:20:39 +04:00
Harutyun Amirjanyan
3673aabe2a Merge pull request #2465 from bcjordan/patch-1
Remove unused variable `text`
2015-04-22 11:25:22 +04:00
Brian Jordan
694d7431b7 Remove unused variable text 2015-04-21 14:58:29 -07:00
nightwing
89b9a8ac72 address review comments 2015-04-20 18:25:32 +04:00
sevin7676
67c7da75b6 fix escape character
was using wrong escape char for string, sqlserver uses double single
quote to escape a single quote
2015-04-20 08:52:03 -04:00
sevin7676
662cd11975 no cache as its storing reference in filtered list 2015-04-20 05:08:54 -04:00
sevin7676
68d531ecb2 cleanup 2015-04-20 04:52:18 -04:00
sevin7676
e58fa3e6d7 remove completionModifer, one off for SQL Server Mode 2015-04-20 04:50:25 -04:00
nightwing
e610365e67 fix #2432 setPolling(false) doesn't turn off polling 2015-04-20 01:11:10 +04:00
nightwing
65b2cf2855 update test for rust mode 2015-04-19 20:35:57 +04:00
nightwing
2008ab813f fix bracket matching in modes imported from textmate 2015-04-19 20:29:28 +04:00
nightwing
ecb699aa11 support converting from cson 2015-04-19 20:28:12 +04:00
nightwing
63687f693b fix #2441 function highlighting in rust mode 2015-04-19 20:27:07 +04:00
nightwing
685ba18451 fix #2452 . is a valid XML tagname character 2015-04-19 20:05:25 +04:00
sevin7676
1ec6eb7b5d shorter names 2015-04-19 11:59:31 -04:00
sevin7676
1027dcea7c cache modifier 2015-04-19 11:52:54 -04:00
sevin7676
961f8c4893 completion modifier for SQL and JavaScript 2015-04-19 11:24:30 -04:00
sevin7676
27284cd29f added completionModifier
allows a highlight rule modify keyword completions
2015-04-19 11:23:10 -04:00
nightwing
04f4292fbc enable Emmet for handlebars mode 2015-04-19 17:34:22 +04:00
nightwing
4e6d48bf2e make sure operationEnd events are not emitted to wrong session 2015-04-19 17:34:22 +04:00
nightwing
80f43beb73 fix typo 2015-04-19 17:34:04 +04:00
sevin7676
cf0c81a25f more snippets 2015-04-19 08:37:22 -04:00
sevin7676
ee90854917 bug fix & typo fix 2015-04-19 08:18:04 -04:00
nightwing
ff4429dd5a fixes for emacs mode 2015-04-19 15:50:22 +04:00
nightwing
487408e84d fix +6291 Hard to tell what pane has focus in Vim mode 2015-04-19 15:50:06 +04:00
nightwing
2713d0a8db center cursor after vim jumplist motions
Conflicts:
	lib/ace/editor.js
2015-04-19 15:49:41 +04:00
nightwing
b0ce5630c9 add support for bindkey.position 2015-04-19 15:48:58 +04:00
Harutyun Amirjanyan
d89311e596 Merge pull request #2456 from kevinushey/bugfix/vim-normal-mode-yank
[vim] define 'Y' as 'keyToKey' mapping (fixes #2455)
2015-04-19 02:26:47 +04:00
Kevin Ushey
5482db1c4d [vim] fix 'Y' behaviour in visual mode 2015-04-18 15:19:28 -07:00
nightwing
eb70d5a6c8 Merge remote-tracking branch 'remotes/origin/master'
Conflicts:
	lib/ace/document.js
2015-04-19 01:04:25 +04:00
Harutyun Amirjanyan
abe0286420 Merge pull request #2458 from ajaxorg/vim
update vim mode
2015-04-18 22:00:47 +04:00
nightwing
094b8a147a update vim mode 2015-04-18 21:01:11 +04:00
Harutyun Amirjanyan
f0d01b93d4 Merge pull request #2457 from sevin7676/master
Add SQL Server (Microsoft SQL) Mode
2015-04-18 19:56:27 +04:00
nightwing
ef9cc542e7 fixes for indentedSoftWrap option 2015-04-18 19:53:49 +04:00
sevin7676
73808101cd cleanup 2015-04-18 10:06:55 -04:00
nightwing
0753f9aa12 Merge remote-tracking branch 'remotes/pull/2187' 2015-04-18 18:00:14 +04:00
Harutyun Amirjanyan
f270b4ae69 Merge pull request #2421 from mortalis13/master
Added new Sublime theme
2015-04-18 17:53:16 +04:00
sevin7676
121e0e51f4 add integer 2015-04-18 09:43:13 -04:00
sevin7676
846c2fb3d3 fix space 2015-04-18 09:35:39 -04:00
sevin7676
cd1c5a42c9 cleanup 2015-04-18 09:21:09 -04:00
sevin7676
282331b133 use pound as its the typical method 2015-04-18 09:12:11 -04:00
sevin7676
db0313f2ad fix case 2015-04-18 09:09:05 -04:00
sevin7676
37a80b35da missing execute in demo doc 2015-04-18 09:05:36 -04:00
sevin7676
75f66697f6 more cleanup 2015-04-18 08:55:29 -04:00
sevin7676
32847a6761 clean up 2015-04-18 08:53:11 -04:00
sevin7676
0d0b0b4356 updated demo doc and snippets 2015-04-18 08:45:13 -04:00
sevin7676
a0a31e16a2 cleanup 2015-04-18 08:27:22 -04:00
sevin7676
295ae4dc81 make pound optional for region 2015-04-18 08:25:47 -04:00
sevin7676
d38849ef9f added doc comment highlight to fix folding 2015-04-18 08:24:59 -04:00
sevin7676
184df6d18e inherit cstyle... trying to figure out best end marker 2015-04-18 07:29:10 -04:00
sevin7676
ff0cc12efc folding partially working.. 2015-04-18 06:37:29 -04:00
Morgan Yarbrough
1b9c8bfc88 FOLDING 2015-04-17 14:24:38 -04:00
Morgan Yarbrough
e42bc9a265 progress, and about to work on folding 2015-04-17 14:09:38 -04:00
Morgan Yarbrough
12be220297 even more keywords! 2015-04-17 12:53:42 -04:00
Morgan Yarbrough
7ae5c862c2 progress but not working yet 2015-04-17 11:17:31 -04:00
sevin7676
d8f7003fb8 add null back 2015-04-17 10:03:56 -04:00
sevin7676
76ac79f116 more progress 2015-04-17 10:00:13 -04:00
sevin7676
1a6e2f83f2 small fixes 2015-04-17 09:35:58 -04:00
sevin7676
6b62974118 good progress 2015-04-17 09:28:56 -04:00
sevin7676
461faa9184 more progress 2015-04-17 08:37:54 -04:00
sevin7676
ede82e7137 progress- save comments for reuse here 2015-04-17 08:11:21 -04:00
sevin7676
f0b3aa0a6f PARTIAL 2015-04-17 07:37:17 -04:00
mortalis13
fb5f272f81 Rename Sublime theme to iPlastic 2015-04-15 21:49:38 +03:00
mortalis13
c458f96d3a Edited lib/ace/sublime.css 2015-04-10 22:19:14 +03:00
Harutyun Amirjanyan
6070fe96f7 Merge pull request #2407 from xixixao/configure-block-select
Add configuration option for block select
2015-04-09 14:56:55 +04:00
Harutyun Amirjanyan
6a2d3fcb09 Merge pull request #2408 from bostikforever/vb-case-insensitive
VBScript is case insensitive
2015-04-09 14:52:56 +04:00
Harutyun Amirjanyan
8b29f7f3c9 Merge pull request #2411 from saxbophone/master
Wider SQL Command and Data Types Coverage
2015-04-09 14:51:33 +04:00
Harutyun Amirjanyan
48de4711eb Merge pull request #2418 from xixixao/selection-zero-height
Remove 0 height selection highlight
2015-04-09 14:50:26 +04:00
nightwing
bb3fa62824 Merge commit '510d060cb2' 2015-04-09 14:20:50 +04:00
Harutyun Amirjanyan
6bdc0d6cbb Merge pull request #2440 from grit96/patch-1
Make print margin in cobalt more visible
2015-04-09 14:20:07 +04:00
nightwing
510d060cb2 cleanup 2015-04-09 14:09:03 +04:00
Geraint White
da8d545985 Make print margin in cobalt more visible 2015-04-09 09:14:21 +01:00
César Izurieta
4f655e71d9 Make deepCopy work correctly with arrays 2015-04-05 04:39:36 -03:00
nightwing
8f686eb795 release v1.1.9 2015-04-03 13:43:18 +04:00
nightwing
6fad60f546 tweaks for the new release 2015-04-03 13:30:00 +04:00
nightwing
1ae86f896a update vim mode 2015-04-03 13:29:10 +04:00
nightwing
4e4df645cc add adoc extension for asciidoc files 2015-04-03 13:29:10 +04:00
Joshua Saxby
0bf729d88f added important keywords and data types missed out 2015-03-27 22:21:42 +00:00
Joshua Saxby
cc40177114 Revert "add some new types and change the type of existing keywords"
This reverts commit fcb4023e52.
2015-03-27 22:11:41 +00:00
Joshua Saxby
fcb4023e52 add some new types and change the type of existing keywords 2015-03-27 22:10:02 +00:00
mortalis
22f802a9ff new sublime theme 2015-03-27 12:37:59 +02:00
xixixao
14a8e1f5d9 Remove 0 height selection highlight 2015-03-25 18:07:38 +00:00
Harutyun Amirjanyan
a2e05ac438 Merge pull request #2410 from kevinushey/bugfix/r-sapply-snippet
correct snippet for 'sapply'
2015-03-21 18:06:48 +04:00
Kevin Ushey
f17c67cd01 correct snippet for 'sapply' 2015-03-19 15:30:41 -07:00
Bolutife Ogunsola
9c6720edca Update tokens test file for vbscript 2015-03-19 19:11:49 +01:00
Bolutife Ogunsola
4dd8eda928 VBScript is case insensitive 2015-03-19 18:03:01 +01:00
xixixao
cb83a974b4 Add configuration option for block select 2015-03-18 21:09:45 +00:00
Ruben Daniels
75556854b9 Merge pull request #2397 from ajaxorg/fix/various
Several small fixes
2015-03-17 15:12:49 -07:00
nightwing
7e9e5aea17 remove old code 2015-03-18 01:57:03 +04:00
nightwing
bb16d65cbb update jshint 2015-03-18 01:55:07 +04:00
Harutyun Amirjanyan
c39134411d Merge pull request #2387 from jmcphers/master
Prevent vim ex commandline from obscuring search results
2015-03-17 10:00:34 +04:00
Harutyun Amirjanyan
cb0816b183 Merge pull request #2399 from kevinushey/patch/vim-colon-selection
[vim] don't select range specifier on `:` insertion
2015-03-17 09:58:58 +04:00
Kevin Ushey
e551b090b7 don't select initial text on ':' 2015-03-16 15:50:31 -07:00
nightwing
c5602489f4 add styling for ace_invisble to all themes 2015-03-15 15:27:48 +04:00
nightwing
1c1d56b3ea make blurred state clearer in github theme 2015-03-15 15:18:10 +04:00
nightwing
a78bf8e5ef update links to emmet.js 2015-03-15 15:00:00 +04:00
nightwing
d9db903190 update rust mode 2015-03-15 15:00:00 +04:00
nightwing
4af37cd722 fix #2395 context menu regression in Firefox on mac 2015-03-15 15:00:00 +04:00
Harutyun Amirjanyan
dd69f5939c Merge pull request #2380 from trystanclarke/master
Fix typeerror "Cannot read property 'container' of undefined" in autocomplete
2015-03-15 00:09:42 +04:00
Harutyun Amirjanyan
cac9e261e3 Merge pull request #2386 from timdp/behaviours-keep-selection
CstyleBehaviour: keeping selections after insertion
2015-03-15 00:01:02 +04:00
Joshua Saxby
0216e8bbfd formatting 2015-03-11 21:27:36 +00:00
Joshua Saxby
38e3452313 added SQL data types 2015-03-11 21:05:54 +00:00
Joshua Saxby
fb7b23e627 started adding missing sql keywords and types 2015-03-11 18:42:21 +00:00
Jonathan McPherson
1b1006ac1d prevent vim ex commandline from obscuring search results (fixes #2384) 2015-03-10 14:17:17 -07:00
Harutyun Amirjanyan
101656ea5c Merge pull request #2385 from mikermcneil/patch-1
makes example work out of the box
2015-03-10 23:41:57 +04:00
Ruben Daniels
6a07619ad2 Merge pull request #2370 from ajaxorg/misc
Misc issues
2015-03-10 12:33:01 -07:00
Tim De Pauw
a5c619bda8 CstyleBehaviour: keeping selections after insertion 2015-03-09 17:44:03 +01:00
Mike McNeil
3adde642dc makes example work out of the box 2015-03-07 18:40:04 -08:00
trystanclarke
967177bbc5 Update autocomplete.js 2015-03-02 09:35:46 +00:00
nightwing
60c639a34b Merge branch 'pull/2375' 2015-02-28 22:17:25 +04:00
nightwing
de9e5226bf add tests from v1.2 branch and increase split size to improve performance 2015-02-28 22:16:19 +04:00
nightwing
76e05b7fd5 fix #2381: keycode for ; is missing 2015-02-28 21:51:18 +04:00
nightwing
2506bb0921 Merge branch pull/2376 2015-02-28 21:43:09 +04:00
nightwing
481bca1b09 use ellipsis character instead of dots 2015-02-28 21:41:30 +04:00
nightwing
01f5846ee3 static highlight can be used without editor.css 2015-02-28 20:40:54 +04:00
Daniel Marcotte
6df244d429 Fit what metadata we can into autocompletes
The whole meta string currently gets dropped from the autocompletes
popup if it doesn't fit.  This leads to confusing autocompletes where
the meta for some entries are missing for no apparent reason.

So, instead of dropping the entire meta string when it doesn't fit,
insert what we can and append "..." to communicate that we clipped it.
2015-02-25 16:43:39 -08:00
Scott Glajch
b5064a4bb3 Fix for issue #2374, maximum call stack exceeded in 64 bit chrome when pasting large chunks. 2015-02-25 13:00:39 -05:00
nightwing
9905267e4d fix gutter in static highlight when wrapping is enabled 2015-02-25 00:14:14 +04:00
nightwing
5ce334e930 update CONTRIBUTING.md 2015-02-24 18:49:59 +04:00
nightwing
7572a9543e update syntax docs 2015-02-24 18:42:15 +04:00
nightwing
4bc34f4eae fix #2341 do not use ace_editor id for the default style 2015-02-18 23:26:22 +04:00
nightwing
8c4173ba11 Merge remote-tracking branch 'remotes/origin/master' 2015-01-18 23:44:18 +04:00
nightwing
56cb246c78 max stack size on chrome is smaller now 2014-12-21 13:46:41 +04:00
nightwing
60dd224d96 remove old delta shim from vim mode 2014-12-20 19:53:51 +04:00
nightwing
067a1ee68b Merge remote-tracking branch 'remotes/origin/master' 2014-12-20 19:51:39 +04:00
nightwing
eec012b24e fix ignoring empty delta 2014-11-20 23:28:09 +04:00
nightwing
004a19855a do not throw for broken anchors since that can break editor 2014-11-20 23:23:46 +04:00
nightwing
d619e4e746 allow passing newLineCharacter ot getValue 2014-11-20 23:02:34 +04:00
nightwing
27264bb9d9 fix infinite loop when inserting more than 0xF000 lines at once 2014-11-20 23:01:53 +04:00
nightwing
a4532dd8b9 Merge remote-tracking branch 'remotes/origin/master' into v-1.2
Conflicts:
	build
	lib/ace/multi_select_test.js
2014-11-11 11:47:04 +04:00
nightwing
64f2fc4015 add newLineCharacter argument to getValue 2014-11-11 11:45:20 +04:00
nightwing
ffaf44ec0b copy insert start position before storing it in undoStack 2014-11-11 11:44:17 +04:00
nightwing
bacaeb07d8 cleanup 2014-11-11 11:40:18 +04:00
nightwing
525fe1ffe3 do not wrap change events in additional e.data 2014-10-18 00:56:13 +04:00
nightwing
bb827051a6 Merge branch 'master' into v-1.2
Conflicts:
	lib/ace/commands/command_manager.js
2014-10-17 19:25:02 +04:00
DanyaPostfactum
6502a3d2cb Update tests for wrap indent 2014-10-12 18:37:52 +10:00
DanyaPostfactum
f625dfeea3 Add indentSubsequentLines to options 2014-10-12 18:37:20 +10:00
DanyaPostfactum
60367772a9 Add wrap indent 2014-10-12 01:56:19 +10:00
nightwing
29023787e5 Merge remote-tracking branch 'remotes/origin/master' into v-1.2
Conflicts:
	build
	lib/ace/document.js
	lib/ace/editor.js
2014-10-05 23:04:57 +04:00
nightwing
ad54d2c46c disabled validateDelta since it breaks autocompletion popup 2014-07-02 22:04:32 +04:00
nightwing
1f7582b5a6 Merge remote-tracking branch 'remotes/origin/master' into v-1.2
Conflicts:
	lib/ace/anchor.js
	lib/ace/keyboard/vim/maps/operators.js
2014-07-02 21:58:13 +04:00
nightwing
ec97ad7904 Merge remote-tracking branch 'remotes/origin/master' into v-1.2
Conflicts:
	build
	lib/ace/document.js
2014-03-31 00:49:41 +04:00
nightwing
27b6d6dcd3 apply arguments max length also includes actual call stack 2014-02-15 00:20:10 +04:00
nightwing
6b60bcbbd6 continue refactoring 2014-02-14 23:52:59 +04:00
nightwing
46f3d77068 simplify apply_delta.js 2014-02-14 22:33:30 +04:00
nightwing
c8d1df203e restore single line delta optimization in anchor.js 2014-02-14 22:32:51 +04:00
nightwing
4299db01bd remove delta.range 2014-02-14 22:32:31 +04:00
nightwing
b5af2c898c Merge remote-tracking branch 'remotes/origin/master'
Conflicts:
	lib/ace/document.js
	lib/ace/editor.js
	lib/ace/undomanager.js
2014-02-14 18:23:03 +04:00
nightwing
c8fca3053c Merge remote-tracking branch 'remotes/origin/master'
Conflicts:
	lib/ace/line_widgets.js
2014-01-16 00:14:34 +04:00
nightwing
8d57d8765f Merge pull request #1745 aldendaniels:master into v-1.2
Refactor document delta handling
2014-01-16 00:11:00 +04:00
aldendaniels
7f1bc7af2f Break out Anchor.onChange helper functions
This should be faster since we don't have to re-initialize the helper
functions each time Anchor.onChange is fired.
2014-01-11 15:48:38 -06:00
aldendaniels
6b280bf6bb Code review fixes (mostly formatting)
- Fix unconventional '{' formatting
- Reformat `UndoManager` changes
- Revert change from `insertInLine` to `insert` in text.js
2014-01-11 15:23:20 -06:00
aldendaniels
35a27fd1ba Treat deltas with empty ranges as NOOPs 2014-01-11 14:45:08 -06:00
aldendaniels
ddd695ee3f Store single-line deltas as .text instead of .lines in undo history
Stores single-line delta content as .text instead of .lines in undo
history. This is done without modifying the original delta object in
case the caller still retains a handle to the original.
2014-01-11 14:43:47 -06:00
aldendaniels
f59708a5ba Add a doNotValidate param to applyDelta
Set it to true in insertInLine/removeInLine.

Also sped up indent/dedent by using insertInLine and removeInLine.
2014-01-11 12:00:10 -06:00
aldendaniels
ef0e8da522 Fix / complete validateDelta
This uncovered the fact that until now delta.range had not always been a
Range object. This inconsistency has been resolved by my changes in
mirror.js.
2014-01-11 11:20:34 -06:00
aldendaniels
08edcdfc98 Stop doing a line-by-line splicing in applyDelta
Also brings back the functionality where large deltas are split into
smaller deltas so that .splice.apply() calls will work.
2014-01-10 22:49:17 -06:00
aldendaniels
3a048cdf61 Bring back insertInLine
Avoids an extra $split call.
2014-01-08 22:51:39 -06:00
aldendaniels
f2a2e4e1a8 Rename the 'delete' delta action to 'remove'
Matches previous naming convention.
2014-01-08 22:18:05 -06:00
aldendaniels
6fe381f633 Rename insertText back to insert 2014-01-08 22:00:11 -06:00
aldendaniels
91df7cd663 Revert "Stop using splice.appy() in ace"
This reverts commit 8624ab8dcb.
2014-01-08 21:39:30 -06:00
aldendaniels
8624ab8dcb Stop using splice.appy() in ace
Since .apply() can't handle more than 65535 parameters, splice.apply()
is brittle. It's also hard to read. This replaces splice.apply() calls
throughout ace code with lang.spliceIntoArray().
2014-01-04 01:59:30 -06:00
aldendaniels
b503e65e03 Break on applyDelta into its own module
This makes it possible to break out helper functions without exposing
them to the rest of the document class. Also, long term, we may want to
have a stand-alone test suite for applyDelta, so it makes sense in its
own file.

All other changes involve syntax corrections (some syntax issues were
mine, others pre-existed) to make the documentation compilation work.
2014-01-03 14:59:22 -06:00
aldendaniels
612478e39f Speed up single-line deltas
2e6f12725b slowed down the application of
deltas that only affect a single line. The slow-down, though trivial for
a single line, is significant for operations than separately modify
thousands of rows (such as indenting a large document).

This commit speeds up single-line deltas by avoiding unnecessary calls
to splitLine() and joinLineWithNext().
2014-01-01 14:45:54 -06:00
aldendaniels
810e196cc6 Use console.warn for deprecated methods
console.warn makes better sense than console.log and matches similar
warnings in ace (see gutter.js for example).
2014-01-01 12:06:19 -06:00
aldendaniels
026af74016 Fix render bugs
Both were introduced in 2e6f12725b.
2014-01-01 12:04:12 -06:00
aldendaniels
27768230c8 Maintain public API and update coding convention
This seeks to keep the public API in-tact while improving method names
within ace by keeping the old methods as wrappers around the new
better-named methods.

For example, document.insert() now simply calls document.insertText()
and warns the caller via a console.log() that they are using a
deprecated method.

I've also updated the coding style of my changes (where I noticed
discrepancies) to match the rest of Ace.
2014-01-01 11:05:27 -06:00
aldendaniels
2e6f12725b #1744: Refactor document delta handling
Refactor delta handling code to:

- Combine the "insertText" and "insertLines" delta types into a single
"insert" delta type

- Combine the "removeText" and "removeLines" delta types into a single
"remove" delta type

- Make all document mutations in a single applyDelta function.

- Add basic delta validation (more needed . . . see TODOs)

- Rework anchor logic to handle new delta types (also simplified)

- Rename "insert()" to "insertText()" and "remove()" to "removeText()"

- Rename "insertLines()" to "insertFullLines()" and "removeLines()" to
"removeFullLines()"

See related issue for more information. All tests are passing and the
changes appear functional under preliminary testing, but careful review
and testing will be necessary.
2014-01-01 00:41:45 -06:00
141 changed files with 5508 additions and 2166 deletions

View file

@ -7,16 +7,9 @@ Feel free to fork and improve/enhance Ace any way you want. If you feel that the
There are two versions of the agreement: There are two versions of the agreement:
1. [The Individual CLA](https://github.com/ajaxorg/ace/raw/master/doc/Contributor_License_Agreement-v2.pdf): use this version if you're working on an ajax.org in your spare time, or can clearly claim ownership of copyright in what you'll be submitting. 1. [The Individual CLA](https://docs.google.com/a/c9.io/forms/d/1MfmfrxqD_PNlNsuK0lC2KSelRLxGLGfh_wEcG0ijVvo/viewform): use this version if you're working on the Cloud9 SDK or open source projects in your spare time, or can clearly claim ownership of copyright in what you'll be submitting.
2. [The Corporate CLA](https://github.com/ajaxorg/ace/raw/master/doc/Corporate_Contributor_License_Agreement-v2.pdf): have your corporate lawyer review and submit this if your company is going to be contributing to ajax.org projects 2. [The Corporate CLA](https://docs.google.com/a/c9.io/forms/d/1vFejn4111GdnCNuQ6BfnJDaxdsUEMD4KCo1ayovAfu0/viewform): have your corporate lawyer review and submit this if your company is going to be contributing to the Cloud9 SDK and/or open source projects.
If you want to contribute to an ajax.org project please print the CLA and fill it out and sign it. Then either send it by snail mail or fax to us or send it back scanned (or as a photo) by email. If you want to contribute to the Cloud9 SDK and/or open source projects please go to the online form, fill it out and submit it.
Email: ace+cla@c9.io Happy coding, Cloud9
Fax: +31 (0) 206388953
Address: Ajax.org B.V.
Keizersgracht 241
1016 EA, Amsterdam
the Netherlands

View file

@ -1,3 +1,16 @@
Version 1.2.0-pre
* New Features
- Indented soft wrap (danyaPostfactum)
* API Changes
- unified delta types `{start, end, action, lines}` (Alden Daniels https://github.com/ajaxorg/ace/pull/1745)
- "change" event listeners on session and editor get delta objects directly
2015.04.03 Version 1.1.9
- Small Enhancements and Bugfixes
2014.11.08 Version 1.1.8 2014.11.08 Version 1.1.8
* API Changes * API Changes

View file

@ -79,7 +79,7 @@ By default the editor only supports plain text mode; many other languages are av
The mode can then be used like this: The mode can then be used like this:
```javascript ```javascript
var JavaScriptMode = require("ace/mode/javascript").Mode; var JavaScriptMode = ace.require("ace/mode/javascript").Mode;
editor.getSession().setMode(new JavaScriptMode()); editor.getSession().setMode(new JavaScriptMode());
``` ```

View file

@ -7,14 +7,13 @@
<style type="text/css" media="screen"> <style type="text/css" media="screen">
.ace_editor { .ace_editor {
position: relative !important;
border: 1px solid lightgray; border: 1px solid lightgray;
margin: auto; margin: auto;
height: 200px; height: 200px;
width: 80%; width: 80%;
} }
.scrollmargin { .scrollmargin {
height: 100px; height: 80px;
text-align: center; text-align: center;
} }
</style> </style>
@ -24,6 +23,8 @@
<div class="scrollmargin"></div> <div class="scrollmargin"></div>
<pre id="editor2">minHeight = 2 lines</pre> <pre id="editor2">minHeight = 2 lines</pre>
<div class="scrollmargin"></div> <div class="scrollmargin"></div>
<pre id="editor3" style="width: 40%;"></pre>
<div class="scrollmargin"></div>
<pre id="editor"></pre> <pre id="editor"></pre>
<script src="kitchen-sink/require.js"></script> <script src="kitchen-sink/require.js"></script>
@ -46,6 +47,13 @@ require(["ace/ace"], function(ace) {
editor2.setOption("maxLines", 30); editor2.setOption("maxLines", 30);
editor2.setOption("minLines", 2); editor2.setOption("minLines", 2);
var editor = ace.edit("editor3");
editor.setOptions({
autoScrollEditorIntoView: true,
maxLines: 8
});
editor.renderer.setScrollMargin(10, 10, 10, 10);
var editor = ace.edit("editor"); var editor = ace.edit("editor");
editor.setTheme("ace/theme/tomorrow"); editor.setTheme("ace/theme/tomorrow");
editor.session.setMode("ace/mode/html"); editor.session.setMode("ace/mode/html");

View file

@ -23,7 +23,7 @@
<pre id="editor"></pre> <pre id="editor"></pre>
<!-- load emmet code and snippets compiled for browser --> <!-- load emmet code and snippets compiled for browser -->
<script src="https://nightwing.github.io/emmet-core/emmet.js"></script> <script src="https://cloud9ide.github.io/emmet-core/emmet.js"></script>
<script src="kitchen-sink/require.js"></script> <script src="kitchen-sink/require.js"></script>
<script> <script>

View file

@ -531,7 +531,7 @@ new StatusBar(env.editor, cmdLine.container);
var Emmet = require("ace/ext/emmet"); var Emmet = require("ace/ext/emmet");
net.loadScript("https://nightwing.github.io/emmet-core/emmet.js", function() { net.loadScript("https://cloud9ide.github.io/emmet-core/emmet.js", function() {
Emmet.setCore(window.emmet); Emmet.setCore(window.emmet);
env.editor.setOption("enableEmmet", true); env.editor.setOption("enableEmmet", true);
}); });

View file

@ -39,7 +39,7 @@ function warn() {
s.shift(); // remove the getter s.shift(); // remove the getter
s = s.join("\n"); s = s.join("\n");
// allow easy access to ace in console, but not in ace code // allow easy access to ace in console, but not in ace code
if (!/at Object.InjectedScript.|@debugger eval|snippets:\/{3}/.test(s)) { if (!/at Object.InjectedScript.|@debugger eval|snippets:\/{3}|\(<anonymous>:\d+:\d+\)/.test(s)) {
console.error("trying to access to global variable"); console.error("trying to access to global variable");
} }
} }

View file

@ -0,0 +1,72 @@
-- =============================================
-- Author: Morgan Yarbrough
-- Create date: 4/27/2015
-- Description: Test procedure that shows off language features.
-- Includes non-standard folding with region comments using either
-- line comments or block comments (both are demonstrated below).
-- This mode imitates SSMS and it designed to be used with SQL Server theme.
-- =============================================
CREATE PROCEDURE dbo.TestProcedure
--#region parameters
@vint INT = 1
,@vdate DATE = NULL
,@vdatetime DATETIME = DATEADD(dd, 1, GETDATE())
,@vvarchar VARCHAR(MAX) = ''
--#endregion
AS
BEGIN
/*#region set statements */
SET NOCOUNT ON;
SET XACT_ABORT ON;
SET QUOTED_IDENTIFIER ON;
/*#endregion*/
/**
* These comments will produce a fold widget
*/
-- folding demonstration
SET @vint = CASE
WHEN @vdate IS NULL
THEN 1
ELSE 2
END
-- another folding demonstration
IF @vint = 1
BEGIN
SET @vvarchar = 'one'
SET @vint = DATEDIFF(dd, @vdate, @vdatetime)
END
-- this mode handles strings properly
DECLARE @sql NVARCHAR(4000) = N'SELECT TOP(1) OrderID
FROM Orders
WHERE @OrderDate > GETDATE()'
-- this mode is aware of built in stored procedures
EXECUTE sp_executesql @sql
-- demonstrating some syntax highlighting
SELECT Orders.OrderID
,Customers.CompanyName
,DATEFROMPARTS(YEAR(GETDATE()), 1, 1) AS FirstDayOfYear
FROM Orders
INNER JOIN Customers
ON Orders.CustomerID = Customers.CustomerID
WHERE CompanyName NOT LIKE '%something'
OR CompanyName IS NULL
OR CompanyName IN ('bla', 'nothing')
-- this mode includes snippets
-- place your cusor at the end of the line below and trigger auto complete (Ctrl+Space)
createpr
-- SQL Server allows using keywords as object names (not recommended) as long as they are wrapped in brackets
DATABASE -- keyword
[DATABASE] -- not a keyword
END

View file

@ -2,13 +2,13 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Static Code highlighter using Ace</title> <title>Static Code highlighter using Ace</title>
<meta name="author" content="Matthew Kastor"> <meta name="author" content="Matthew Kastor">
<style type="text/css"> <style type="text/css">
.code { .code {
width: 50%; width: 50%;
position: relative;
white-space: pre-wrap; white-space: pre-wrap;
border: solid lightgrey 1px
} }
</style> </style>
</head> </head>
@ -21,9 +21,8 @@
<div class="code" ace-mode="ace/mode/css" ace-theme="ace/theme/chrome" ace-gutter="true"> <div class="code" ace-mode="ace/mode/css" ace-theme="ace/theme/chrome" ace-gutter="true">
.code { .code {
width: 50%; width: 50%;
position: relative;
white-space: pre-wrap; white-space: pre-wrap;
border: solid lightgrey 1px
} }
</div> </div>
@ -35,6 +34,26 @@ function wobble (flam) {
</pre> </pre>
<div class="code" ace-mode="ace/mode/lua" ace-theme="ace/theme/chrome" ace-gutter="true" style="width: 30em;">
--[[--
num_args takes in 5.1 byte code and extracts the number of arguments from its function header.
--]]--
function int(t)
return t:byte(1) + t:byte(2) * 0x100 + t:byte(3) * 0x10000 + t:byte(4) * 0x1000000
end
function num_args(func)
local dump = string.dump(func)
local offset, cursor = int(dump:sub(13)), offset + 26
--Get the params and var flag (whether there's a ... in the param)
return dump:sub(cursor):byte(), dump:sub(cursor+1):byte()
end
</div>
<script src="kitchen-sink/require.js"></script> <script src="kitchen-sink/require.js"></script>
<script> <script>
require.config({paths: { "ace" : "../lib/ace"}}); require.config({paths: { "ace" : "../lib/ace"}});

View file

@ -2,15 +2,13 @@
* Simple node.js server, which generates the synax highlighted version of itself * Simple node.js server, which generates the synax highlighted version of itself
* using the Ace modes and themes on the server and serving a static web page. * using the Ace modes and themes on the server and serving a static web page.
*/ */
// $'
// include ace search path and modules // include ace search path and modules
require("amd-loader"); require("amd-loader");
// load jsdom, which is required by Ace
require("../../lib/ace/test/mockdom");
var http = require("http"); var http = require("http");
var fs = require("fs"); var fs = require("fs");
var resolve = require("path").resolve;
// load the highlighter and the desired mode and theme // load the highlighter and the desired mode and theme
var highlighter = require("../../lib/ace/ext/static_highlight"); var highlighter = require("../../lib/ace/ext/static_highlight");
@ -20,15 +18,22 @@ var theme = require("../../lib/ace/theme/twilight");
var port = process.env.PORT || 2222; var port = process.env.PORT || 2222;
http.createServer(function(req, res) { http.createServer(function(req, res) {
var url = req.url;
var path = /[^#?\x00]*/.exec(url)[0];
var root = resolve(__dirname + "/../../").replace(/\\/g, "/");
path = resolve(root + "/" + path).replace(/\\/g, "/");
if (path.indexOf(root + "/") != 0)
path = __filename;
res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"}); res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"});
fs.readFile(__filename, "utf8", function(err, data) { fs.readFile(path, "utf8", function(err, data) {
if (err) data = err.message;
var highlighted = highlighter.render(data, new JavaScriptMode(), theme); var highlighted = highlighter.render(data, new JavaScriptMode(), theme);
res.end( res.end(
'<html><body>\n' + '<html><body>\n' +
'<style type="text/css" media="screen">\n' + '<style type="text/css" media="screen">\n' +
highlighted.css + highlighted.css +
'</style>\n' + '</style>\n' +
highlighted.html + highlighted.html +
'</body></html>' '</body></html>'
); );
}); });

View file

@ -18,7 +18,7 @@ $(function() {
}); });
ace.config.loadModule("ace/ext/emmet", function() { ace.config.loadModule("ace/ext/emmet", function() {
ace.require("ace/lib/net").loadScript("http://nightwing.github.io/emmet-core/emmet.js", function() { ace.require("ace/lib/net").loadScript("http://cloud9ide.github.io/emmet-core/emmet.js", function() {
embedded_editor.setOption("enableEmmet", true); embedded_editor.setOption("enableEmmet", true);
editor.setOption("enableEmmet", true); editor.setOption("enableEmmet", true);
}); });

View file

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="../demo/kitchen-sink/require.js"></script>
<script type="text/javascript">
require.config({
paths: { ace: "../lib/ace" },
waitSeconds: 0
});
</script>
</head>
<body>
<p><button onclick="toggleEditor()">Toggle editor</button></p>
<div id="container"></div>
<script>
var editor;
var counter = 0
function toggleEditor() {
if (!editor) {
var root = document.createElement("div");
root.style.height = "100px";
root.setAttribute("id", "editor");
root.textContent = "function foo(items) {\nvar x = 'All this is syntax highlighted';\nreturn x;\n}";
document.getElementById("container").appendChild(root);
editor = ace.edit(root);
if (counter++ % 2)
editor.setTheme("ace/theme/monokai");
else
editor.setTheme("ace/theme/clouds");
editor.session.setMode("ace/mode/javascript");
} else {
editor.destroy();
var el = editor.container;
el.parentNode.removeChild(el);
editor.container = null
editor.renderer = null
editor = null;
var root = document.getElementById("editor")
if (root)
root.parentNode.removeChild(root);
}
}
require(["ace/ace"], function(ace) {
window.ace = ace;
toggleEditor();
})
</script>
</body>
</html>

View file

@ -470,7 +470,6 @@ var fonts = lang.arrayToMap(
<pre><code class="language-javascript">this.$rules = { <pre><code class="language-javascript">this.$rules = {
"start" : [ { "start" : [ {
token : "text", token : "text",
merge : true,
regex : "&lt;\\!\\[CDATA\\[", regex : "&lt;\\!\\[CDATA\\[",
next : "cdata" next : "cdata"
}, },
@ -480,13 +479,7 @@ var fonts = lang.arrayToMap(
regex : "\\]\\]&gt;", regex : "\\]\\]&gt;",
next : "start" next : "start"
}, { }, {
token : "text", defaultToken : "text"
merge : true,
regex : "\\s+"
}, {
token : "text",
merge : true,
regex : ".+"
} ] } ]
};</code></pre> };</code></pre>
<p>In this extremly short sample, we're defining some highlighting rules for when Ace detectes a <code>&lt;![CDATA</code> tag. When one is encountered, the tokenizer moves from <code>start</code> into the <code>cdata</code> state. It remains there, applying the <code>text</code> token to any string it encounters. Finally, when it hits a closing <code>]&gt;</code> symbol, it returns to the <code>start</code> state and continues to tokenize anything else.</p> <p>In this extremly short sample, we're defining some highlighting rules for when Ace detectes a <code>&lt;![CDATA</code> tag. When one is encountered, the tokenizer moves from <code>start</code> into the <code>cdata</code> state. It remains there, applying the <code>text</code> token to any string it encounters. Finally, when it hits a closing <code>]&gt;</code> symbol, it returns to the <code>start</code> state and continues to tokenize anything else.</p>

View file

@ -99,72 +99,54 @@ var Anchor = exports.Anchor = function(doc, row, column) {
* - `value`: An object describing the new Anchor position * - `value`: An object describing the new Anchor position
* *
**/ **/
this.onChange = function(e) { this.onChange = function(delta) {
var delta = e.data; if (delta.start.row == delta.end.row && delta.start.row != this.row)
var range = delta.range;
if (range.start.row == range.end.row && range.start.row != this.row)
return; return;
if (range.start.row > this.row) if (delta.start.row > this.row)
return; return;
if (range.start.row == this.row && range.start.column > this.column) var point = $getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight);
return; this.setPosition(point.row, point.column, true);
var row = this.row;
var column = this.column;
var start = range.start;
var end = range.end;
if (delta.action === "insertText") {
if (start.row === row && start.column <= column) {
if (start.column === column && this.$insertRight) {
// do nothing
} else if (start.row === end.row) {
column += end.column - start.column;
} else {
column -= start.column;
row += end.row - start.row;
}
} else if (start.row !== end.row && start.row < row) {
row += end.row - start.row;
}
} else if (delta.action === "insertLines") {
if (start.row === row && column === 0 && this.$insertRight) {
// do nothing
}
else if (start.row <= row) {
row += end.row - start.row;
}
} else if (delta.action === "removeText") {
if (start.row === row && start.column < column) {
if (end.column >= column)
column = start.column;
else
column = Math.max(0, column - (end.column - start.column));
} else if (start.row !== end.row && start.row < row) {
if (end.row === row)
column = Math.max(0, column - end.column) + start.column;
row -= (end.row - start.row);
} else if (end.row === row) {
row -= end.row - start.row;
column = Math.max(0, column - end.column) + start.column;
}
} else if (delta.action == "removeLines") {
if (start.row <= row) {
if (end.row <= row)
row -= end.row - start.row;
else {
row = start.row;
column = 0;
}
}
}
this.setPosition(row, column, true);
}; };
function $pointsInOrder(point1, point2, equalPointsInOrder) {
var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column;
return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter);
}
function $getTransformedPoint(delta, point, moveIfEqual) {
// Get delta info.
var deltaIsInsert = delta.action == "insert";
var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.end.row - delta.start.row);
var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.end.column - delta.start.column);
var deltaStart = delta.start;
var deltaEnd = deltaIsInsert ? deltaStart : delta.end; // Collapse insert range.
// DELTA AFTER POINT: No change needed.
if ($pointsInOrder(point, deltaStart, moveIfEqual)) {
return {
row: point.row,
column: point.column
};
}
// DELTA BEFORE POINT: Move point by delta shift.
if ($pointsInOrder(deltaEnd, point, !moveIfEqual)) {
return {
row: point.row + deltaRowShift,
column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0)
};
}
// DELTA ENVELOPS POINT (delete only): Move point to delta start.
// TODO warn if delta.action != "remove" ?
return {
row: deltaStart.row,
column: deltaStart.column
};
}
/** /**
* Sets the anchor position to the specified row and column. If `noClip` is `true`, the position is not clipped. * Sets the anchor position to the specified row and column. If `noClip` is `true`, the position is not clipped.

View file

@ -71,7 +71,7 @@ module.exports = {
var doc = new Document("juhu\nkinners"); var doc = new Document("juhu\nkinners");
var anchor = new Anchor(doc, 1, 4); var anchor = new Anchor(doc, 1, 4);
doc.insertLines(1, ["123", "456"]); doc.insertFullLines(1, ["123", "456"]);
assert.position(anchor.getPosition(), 3, 4); assert.position(anchor.getPosition(), 3, 4);
}, },
@ -105,7 +105,7 @@ module.exports = {
var doc = new Document("juhu\nkinners"); var doc = new Document("juhu\nkinners");
var anchor = new Anchor(doc, 1, 4); var anchor = new Anchor(doc, 1, 4);
doc.insertNewLine({row: 0, column: 0}); doc.insertMergedLines({row: 0, column: 0}, ['', '']);
assert.position(anchor.getPosition(), 2, 4); assert.position(anchor.getPosition(), 2, 4);
}, },
@ -113,7 +113,7 @@ module.exports = {
var doc = new Document("juhu\nkinners"); var doc = new Document("juhu\nkinners");
var anchor = new Anchor(doc, 1, 4); var anchor = new Anchor(doc, 1, 4);
doc.insertNewLine({row: 1, column: 2}); doc.insertMergedLines({row: 1, column: 2}, ['', '']);
assert.position(anchor.getPosition(), 2, 2); assert.position(anchor.getPosition(), 2, 2);
}, },
@ -145,7 +145,7 @@ module.exports = {
var doc = new Document("juhu\n1\n2\nkinners"); var doc = new Document("juhu\n1\n2\nkinners");
var anchor = new Anchor(doc, 3, 4); var anchor = new Anchor(doc, 3, 4);
doc.removeLines(1, 2); doc.removeFullLines(1, 2);
assert.position(anchor.getPosition(), 1, 4); assert.position(anchor.getPosition(), 1, 4);
}, },
@ -169,7 +169,7 @@ module.exports = {
var doc = new Document("juhu\nkinners\n123"); var doc = new Document("juhu\nkinners\n123");
var anchor = new Anchor(doc, 1, 5); var anchor = new Anchor(doc, 1, 5);
doc.removeLines(1, 1); doc.removeFullLines(1, 1);
assert.position(anchor.getPosition(), 1, 0); assert.position(anchor.getPosition(), 1, 0);
}, },
@ -208,9 +208,9 @@ module.exports = {
var doc = new Document("juhu\nkinners\n123"); var doc = new Document("juhu\nkinners\n123");
var anchor = new Anchor(doc, 2, 4); var anchor = new Anchor(doc, 2, 4);
doc.removeLines(0, 3); doc.removeFullLines(0, 3);
assert.position(anchor.getPosition(), 0, 0); assert.position(anchor.getPosition(), 0, 0);
doc.insertLines(0, ["a", "b", "c"]); doc.insertFullLines(0, ["a", "b", "c"]);
assert.position(anchor.getPosition(), 3, 0); assert.position(anchor.getPosition(), 3, 0);
assert.equal(doc.getValue(), "a\nb\nc\n"); assert.equal(doc.getValue(), "a\nb\nc\n");
} }

108
lib/ace/apply_delta.js Normal file
View file

@ -0,0 +1,108 @@
/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2010, Ajax.org B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
function throwDeltaError(delta, errorText){
console.log("Invalid Delta:", delta);
throw "Invalid Delta: " + errorText;
}
function positionInDocument(docLines, position) {
return position.row >= 0 && position.row < docLines.length &&
position.column >= 0 && position.column <= docLines[position.row].length;
}
function validateDelta(docLines, delta) {
// Validate action string.
if (delta.action != "insert" && delta.action != "remove")
throwDeltaError(delta, "delta.action must be 'insert' or 'remove'");
// Validate lines type.
if (!(delta.lines instanceof Array))
throwDeltaError(delta, "delta.lines must be an Array");
// Validate range type.
if (!delta.start || !delta.end)
throwDeltaError(delta, "delta.start/end must be an present");
// Validate that the start point is contained in the document.
var start = delta.start;
if (!positionInDocument(docLines, delta.start))
throwDeltaError(delta, "delta.start must be contained in document");
// Validate that the end point is contained in the document (remove deltas only).
var end = delta.end;
if (delta.action == "remove" && !positionInDocument(docLines, end))
throwDeltaError(delta, "delta.end must contained in document for 'remove' actions");
// Validate that the .range size matches the .lines size.
var numRangeRows = end.row - start.row;
var numRangeLastLineChars = (end.column - (numRangeRows == 0 ? start.column : 0));
if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars)
throwDeltaError(delta, "delta.range must match delta lines");
}
exports.applyDelta = function(docLines, delta, doNotValidate) {
// disabled validation since it breaks autocompletion popup
// if (!doNotValidate)
// validateDelta(docLines, delta);
var row = delta.start.row;
var startColumn = delta.start.column;
var line = docLines[row] || "";
switch (delta.action) {
case "insert":
var lines = delta.lines;
if (lines.length === 1) {
docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn);
} else {
var args = [row, 1].concat(delta.lines);
docLines.splice.apply(docLines, args);
docLines[row] = line.substring(0, startColumn) + docLines[row];
docLines[row + delta.lines.length - 1] += line.substring(startColumn);
}
break;
case "remove":
var endColumn = delta.end.column;
var endRow = delta.end.row;
if (row === endRow) {
docLines[row] = line.substring(0, startColumn) + line.substring(endColumn);
} else {
docLines.splice(
row, endRow - row + 1,
line.substring(0, startColumn) + docLines[endRow].substring(endColumn)
);
}
break;
}
}
});

View file

@ -100,7 +100,7 @@ var Autocomplete = function() {
var rect = editor.container.getBoundingClientRect(); var rect = editor.container.getBoundingClientRect();
pos.top += rect.top - renderer.layerConfig.offset; pos.top += rect.top - renderer.layerConfig.offset;
pos.left += rect.left - editor.renderer.scrollLeft; pos.left += rect.left - editor.renderer.scrollLeft;
pos.left += renderer.$gutterLayer.gutterWidth; pos.left += renderer.gutterWidth;
this.popup.show(pos, lineHeight); this.popup.show(pos, lineHeight);
} else if (keepPopupPosition && !prefix) { } else if (keepPopupPosition && !prefix) {
@ -142,10 +142,11 @@ var Autocomplete = function() {
// we have to check if activeElement is a child of popup because // we have to check if activeElement is a child of popup because
// on IE preventDefault doesn't stop scrollbar from being focussed // on IE preventDefault doesn't stop scrollbar from being focussed
var el = document.activeElement; var el = document.activeElement;
var text = this.editor.textInput.getElement() var text = this.editor.textInput.getElement();
if (el != text && this.popup && el.parentNode != this.popup.container var fromTooltip = e.relatedTarget && e.relatedTarget == this.tooltipNode;
&& el != this.tooltipNode && e.relatedTarget != this.tooltipNode var container = this.popup && this.popup.container;
&& e.relatedTarget != text if (el != text && el.parentNode != container && !fromTooltip
&& el != this.tooltipNode && e.relatedTarget != text
) { ) {
this.detach(); this.detach();
} }
@ -205,7 +206,6 @@ var Autocomplete = function() {
"Ctrl-Down|Ctrl-End": function(editor) { editor.completer.goTo("end"); }, "Ctrl-Down|Ctrl-End": function(editor) { editor.completer.goTo("end"); },
"Esc": function(editor) { editor.completer.detach(); }, "Esc": function(editor) { editor.completer.detach(); },
"Space": function(editor) { editor.completer.detach(); editor.insert(" ");},
"Return": function(editor) { return editor.completer.insertMatch(); }, "Return": function(editor) { return editor.completer.insertMatch(); },
"Shift-Return": function(editor) { editor.completer.insertMatch(true); }, "Shift-Return": function(editor) { editor.completer.insertMatch(true); },
"Tab": function(editor) { "Tab": function(editor) {
@ -350,7 +350,7 @@ var Autocomplete = function() {
doc = selected; doc = selected;
if (typeof doc == "string") if (typeof doc == "string")
doc = {docText: doc} doc = {docText: doc};
if (!doc || !(doc.docHTML || doc.docText)) if (!doc || !(doc.docHTML || doc.docText))
return this.hideDocTooltip(); return this.hideDocTooltip();
this.showDocTooltip(doc); this.showDocTooltip(doc);
@ -417,7 +417,7 @@ Autocomplete.startCommand = {
bindKey: "Ctrl-Space|Ctrl-Shift-Space|Alt-Space" bindKey: "Ctrl-Space|Ctrl-Shift-Space|Alt-Space"
}; };
var FilteredList = function(array, filterText, mutateData) { var FilteredList = function(array, filterText) {
this.all = array; this.all = array;
this.filtered = array; this.filtered = array;
this.filterText = filterText || ""; this.filterText = filterText || "";

View file

@ -31,7 +31,6 @@
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict"; "use strict";
var EditSession = require("../edit_session").EditSession;
var Renderer = require("../virtual_renderer").VirtualRenderer; var Renderer = require("../virtual_renderer").VirtualRenderer;
var Editor = require("../editor").Editor; var Editor = require("../editor").Editor;
var Range = require("../range").Range; var Range = require("../range").Range;
@ -197,8 +196,12 @@ var AcePopup = function(parentNode) {
if (data.meta) { if (data.meta) {
var maxW = popup.renderer.$size.scrollerWidth / popup.renderer.layerConfig.characterWidth; var maxW = popup.renderer.$size.scrollerWidth / popup.renderer.layerConfig.characterWidth;
if (data.meta.length + data.caption.length < maxW - 2) var metaData = data.meta;
tokens.push({type: "rightAlignedText", value: data.meta}); if (metaData.length + data.caption.length > maxW - 2) {
// trim meta to fit this popup and add ellipsis
metaData = metaData.substr(0, maxW - data.caption.length - 3) + "\u2026"
}
tokens.push({type: "rightAlignedText", value: metaData});
} }
return tokens; return tokens;
}; };
@ -217,8 +220,8 @@ var AcePopup = function(parentNode) {
popup.data = []; popup.data = [];
popup.setData = function(list) { popup.setData = function(list) {
popup.data = list || [];
popup.setValue(lang.stringRepeat("\n", list.length), -1); popup.setValue(lang.stringRepeat("\n", list.length), -1);
popup.data = list || [];
popup.setRow(0); popup.setRow(0);
}; };
popup.getData = function(row) { popup.getData = function(row) {
@ -338,4 +341,4 @@ dom.importCssString("\
exports.AcePopup = AcePopup; exports.AcePopup = AcePopup;
}); });

View file

@ -68,11 +68,10 @@ var BackgroundTokenizer = function(tokenizer, editor) {
var endLine = -1; var endLine = -1;
var doc = self.doc; var doc = self.doc;
var startLine = currentLine;
while (self.lines[currentLine]) while (self.lines[currentLine])
currentLine++; currentLine++;
var startLine = currentLine;
var len = doc.getLength(); var len = doc.getLength();
var processedLines = 0; var processedLines = 0;
self.running = false; self.running = false;
@ -172,13 +171,12 @@ var BackgroundTokenizer = function(tokenizer, editor) {
} }
this.$updateOnChange = function(delta) { this.$updateOnChange = function(delta) {
var range = delta.range; var startRow = delta.start.row;
var startRow = range.start.row; var len = delta.end.row - startRow;
var len = range.end.row - startRow;
if (len === 0) { if (len === 0) {
this.lines[startRow] = null; this.lines[startRow] = null;
} else if (delta.action == "removeText" || delta.action == "removeLines") { } else if (delta.action == "remove") {
this.lines.splice(startRow, len + 1, null); this.lines.splice(startRow, len + 1, null);
this.states.splice(startRow, len + 1, null); this.states.splice(startRow, len + 1, null);
} else { } else {

View file

@ -75,6 +75,49 @@ module.exports = {
forceTokenize(doc) forceTokenize(doc)
testStates(doc, ["comment_regex_allowed", "start", "no_regex"]) testStates(doc, ["comment_regex_allowed", "start", "no_regex"])
},
"test background tokenizer sends update event" : function() {
var doc = new EditSession([
"/*",
"var",
"juhu",
"*/"
]);
doc.setMode("./mode/javascript");
var updateEvent = null;
doc.bgTokenizer.on("update", function(e) {
updateEvent = e.data;
});
function checkEvent(first, last) {
assert.ok(!updateEvent, "unneccessary update event");
doc.bgTokenizer.running = 1;
doc.bgTokenizer.$worker();
assert.ok(updateEvent);
assert.equal([first, last] + "",
[updateEvent.first, updateEvent.last] + "")
updateEvent = null;
}
forceTokenize(doc);
var comment = "comment_regex_allowed";
testStates(doc, [comment, comment, comment, "start"]);
doc.remove(new Range(0,0,0,2));
testStates(doc, [comment, comment, comment, "start"]);
checkEvent(0, 3);
testStates(doc, ["start", "no_regex", "no_regex", "regex"]);
// insert /* and and press down several times quickly
doc.insert({row:0, column:0}, "/*");
doc.getTokens(0);
doc.getTokens(1);
doc.getTokens(2);
checkEvent(0, 3);
forceTokenize(doc);
testStates(doc, [comment, comment, comment, "start"]);
} }
}; };

View file

@ -423,6 +423,12 @@ exports.commands = [{
exec: function() {}, exec: function() {},
passEvent: true, passEvent: true,
readOnly: true readOnly: true
}, {
name: "copy",
exec: function(editor) {
// placeholder for replay macro
},
readOnly: true
}, },
// commands disabled in readOnly mode // commands disabled in readOnly mode
@ -439,6 +445,12 @@ exports.commands = [{
}, },
scrollIntoView: "cursor", scrollIntoView: "cursor",
multiSelectAction: "forEach" multiSelectAction: "forEach"
}, {
name: "paste",
exec: function(editor, args) {
editor.$handlePaste(args);
},
scrollIntoView: "cursor"
}, { }, {
name: "removeline", name: "removeline",
bindKey: bindKey("Ctrl-D", "Command-D"), bindKey: bindKey("Ctrl-D", "Command-D"),

View file

@ -69,18 +69,14 @@ exports.iSearchCommands = [{
bindKey: {win: "Ctrl-F", mac: "Command-F"}, bindKey: {win: "Ctrl-F", mac: "Command-F"},
exec: function(iSearch) { exec: function(iSearch) {
iSearch.cancelSearch(true); iSearch.cancelSearch(true);
}, }
readOnly: true,
isIncrementalSearchCommand: true
}, { }, {
name: "searchForward", name: "searchForward",
bindKey: {win: "Ctrl-S|Ctrl-K", mac: "Ctrl-S|Command-G"}, bindKey: {win: "Ctrl-S|Ctrl-K", mac: "Ctrl-S|Command-G"},
exec: function(iSearch, options) { exec: function(iSearch, options) {
options.useCurrentOrPrevSearch = true; options.useCurrentOrPrevSearch = true;
iSearch.next(options); iSearch.next(options);
}, }
readOnly: true,
isIncrementalSearchCommand: true
}, { }, {
name: "searchBackward", name: "searchBackward",
bindKey: {win: "Ctrl-R|Ctrl-Shift-K", mac: "Ctrl-R|Command-Shift-G"}, bindKey: {win: "Ctrl-R|Ctrl-Shift-K", mac: "Ctrl-R|Command-Shift-G"},
@ -88,42 +84,30 @@ exports.iSearchCommands = [{
options.useCurrentOrPrevSearch = true; options.useCurrentOrPrevSearch = true;
options.backwards = true; options.backwards = true;
iSearch.next(options); iSearch.next(options);
}, }
readOnly: true,
isIncrementalSearchCommand: true
}, { }, {
name: "extendSearchTerm", name: "extendSearchTerm",
exec: function(iSearch, string) { exec: function(iSearch, string) {
iSearch.addString(string); iSearch.addString(string);
}, }
readOnly: true,
isIncrementalSearchCommand: true
}, { }, {
name: "extendSearchTermSpace", name: "extendSearchTermSpace",
bindKey: "space", bindKey: "space",
exec: function(iSearch) { iSearch.addString(' '); }, exec: function(iSearch) { iSearch.addString(' '); }
readOnly: true,
isIncrementalSearchCommand: true
}, { }, {
name: "shrinkSearchTerm", name: "shrinkSearchTerm",
bindKey: "backspace", bindKey: "backspace",
exec: function(iSearch) { exec: function(iSearch) {
iSearch.removeChar(); iSearch.removeChar();
}, }
readOnly: true,
isIncrementalSearchCommand: true
}, { }, {
name: 'confirmSearch', name: 'confirmSearch',
bindKey: 'return', bindKey: 'return',
exec: function(iSearch) { iSearch.deactivate(); }, exec: function(iSearch) { iSearch.deactivate(); }
readOnly: true,
isIncrementalSearchCommand: true
}, { }, {
name: 'cancelSearch', name: 'cancelSearch',
bindKey: 'esc|Ctrl-G', bindKey: 'esc|Ctrl-G',
exec: function(iSearch) { iSearch.deactivate(true); }, exec: function(iSearch) { iSearch.deactivate(true); }
readOnly: true,
isIncrementalSearchCommand: true
}, { }, {
name: 'occurisearch', name: 'occurisearch',
bindKey: 'Ctrl-O', bindKey: 'Ctrl-O',
@ -131,9 +115,7 @@ exports.iSearchCommands = [{
var options = oop.mixin({}, iSearch.$options); var options = oop.mixin({}, iSearch.$options);
iSearch.deactivate(); iSearch.deactivate();
occurStartCommand.exec(iSearch.$editor, options); occurStartCommand.exec(iSearch.$editor, options);
}, }
readOnly: true,
isIncrementalSearchCommand: true
}, { }, {
name: "yankNextWord", name: "yankNextWord",
bindKey: "Ctrl-w", bindKey: "Ctrl-w",
@ -142,9 +124,7 @@ exports.iSearchCommands = [{
range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorWordRight(); }), range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorWordRight(); }),
string = ed.session.getTextRange(range); string = ed.session.getTextRange(range);
iSearch.addString(string); iSearch.addString(string);
}, }
readOnly: true,
isIncrementalSearchCommand: true
}, { }, {
name: "yankNextChar", name: "yankNextChar",
bindKey: "Ctrl-Alt-y", bindKey: "Ctrl-Alt-y",
@ -153,15 +133,11 @@ exports.iSearchCommands = [{
range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorRight(); }), range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorRight(); }),
string = ed.session.getTextRange(range); string = ed.session.getTextRange(range);
iSearch.addString(string); iSearch.addString(string);
}, }
readOnly: true,
isIncrementalSearchCommand: true
}, { }, {
name: 'recenterTopBottom', name: 'recenterTopBottom',
bindKey: 'Ctrl-l', bindKey: 'Ctrl-l',
exec: function(iSearch) { iSearch.$editor.execCommand('recenterTopBottom'); }, exec: function(iSearch) { iSearch.$editor.execCommand('recenterTopBottom'); }
readOnly: true,
isIncrementalSearchCommand: true
}, { }, {
name: 'selectAllMatches', name: 'selectAllMatches',
bindKey: 'Ctrl-space', bindKey: 'Ctrl-space',
@ -173,18 +149,19 @@ exports.iSearchCommands = [{
return ranges.concat(ea ? ea : []); }, []) : []; return ranges.concat(ea ? ea : []); }, []) : [];
iSearch.deactivate(false); iSearch.deactivate(false);
ranges.forEach(ed.selection.addRange.bind(ed.selection)); ranges.forEach(ed.selection.addRange.bind(ed.selection));
}, }
readOnly: true,
isIncrementalSearchCommand: true
}, { }, {
name: 'searchAsRegExp', name: 'searchAsRegExp',
bindKey: 'Alt-r', bindKey: 'Alt-r',
exec: function(iSearch) { exec: function(iSearch) {
iSearch.convertNeedleToRegExp(); iSearch.convertNeedleToRegExp();
}, }
readOnly: true, }].map(function(cmd) {
isIncrementalSearchCommand: true cmd.readOnly = true;
}]; cmd.isIncrementalSearchCommand = true;
cmd.scrollIntoView = "animate-cursor";
return cmd;
});
function IncrementalSearchKeyboardHandler(iSearch) { function IncrementalSearchKeyboardHandler(iSearch) {
this.$iSearch = iSearch; this.$iSearch = iSearch;
@ -192,7 +169,7 @@ function IncrementalSearchKeyboardHandler(iSearch) {
oop.inherits(IncrementalSearchKeyboardHandler, HashHandler); oop.inherits(IncrementalSearchKeyboardHandler, HashHandler);
;(function() { (function() {
this.attach = function(editor) { this.attach = function(editor) {
var iSearch = this.$iSearch; var iSearch = this.$iSearch;
@ -201,15 +178,19 @@ oop.inherits(IncrementalSearchKeyboardHandler, HashHandler);
if (!e.command.isIncrementalSearchCommand) return undefined; if (!e.command.isIncrementalSearchCommand) return undefined;
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
return e.command.exec(iSearch, e.args || {}); var scrollTop = editor.session.getScrollTop();
var result = e.command.exec(iSearch, e.args || {});
editor.renderer.scrollCursorIntoView(null, 0.5);
editor.renderer.animateScrolling(scrollTop);
return result;
}); });
} };
this.detach = function(editor) { this.detach = function(editor) {
if (!this.$commandExecHandler) return; if (!this.$commandExecHandler) return;
editor.commands.removeEventListener('exec', this.$commandExecHandler); editor.commands.removeEventListener('exec', this.$commandExecHandler);
delete this.$commandExecHandler; delete this.$commandExecHandler;
} };
var handleKeyboard$super = this.handleKeyboard; var handleKeyboard$super = this.handleKeyboard;
this.handleKeyboard = function(data, hashId, key, keyCode) { this.handleKeyboard = function(data, hashId, key, keyCode) {
@ -222,7 +203,7 @@ oop.inherits(IncrementalSearchKeyboardHandler, HashHandler);
if (extendCmd) { return {command: extendCmd, args: key}; } if (extendCmd) { return {command: extendCmd, args: key}; }
} }
return {command: "null", passEvent: hashId == 0 || hashId == 4}; return {command: "null", passEvent: hashId == 0 || hashId == 4};
} };
}).call(IncrementalSearchKeyboardHandler.prototype); }).call(IncrementalSearchKeyboardHandler.prototype);

View file

@ -39,7 +39,7 @@ var AppConfig = require("./lib/app_config").AppConfig;
module.exports = exports = new AppConfig(); module.exports = exports = new AppConfig();
var global = (function() { var global = (function() {
return this; return this || typeof window != "undefined" && window;
})(); })();
var options = { var options = {

View file

@ -422,3 +422,30 @@
position: absolute; position: absolute;
z-index: 8; z-index: 8;
} }
/*
styles = []
for (var i = 1; i < 16; i++) {
styles.push(".ace_br" + i + "{" + (
["top-left", "top-right", "bottom-right", "bottom-left"]
).map(function(x, j) {
return i & (1<<j) ? "border-" + x + "-radius: 3px;" : ""
}).filter(Boolean).join(" ") + "}")
}
styles.join("\n")
*/
.ace_br1 {border-top-left-radius : 3px;}
.ace_br2 {border-top-right-radius : 3px;}
.ace_br3 {border-top-left-radius : 3px; border-top-right-radius: 3px;}
.ace_br4 {border-bottom-right-radius: 3px;}
.ace_br5 {border-top-left-radius : 3px; border-bottom-right-radius: 3px;}
.ace_br6 {border-top-right-radius : 3px; border-bottom-right-radius: 3px;}
.ace_br7 {border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px;}
.ace_br8 {border-bottom-left-radius : 3px;}
.ace_br9 {border-top-left-radius : 3px; border-bottom-left-radius: 3px;}
.ace_br10{border-top-right-radius : 3px; border-bottom-left-radius: 3px;}
.ace_br11{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-left-radius: 3px;}
.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}
.ace_br13{border-top-left-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}
.ace_br14{border-top-right-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}
.ace_br15{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}

View file

@ -32,36 +32,36 @@ define(function(require, exports, module) {
"use strict"; "use strict";
var oop = require("./lib/oop"); var oop = require("./lib/oop");
var applyDelta = require("./apply_delta").applyDelta;
var EventEmitter = require("./lib/event_emitter").EventEmitter; var EventEmitter = require("./lib/event_emitter").EventEmitter;
var Range = require("./range").Range; var Range = require("./range").Range;
var Anchor = require("./anchor").Anchor; var Anchor = require("./anchor").Anchor;
/** /**
* Contains the text of the document. Document can be attached to several [[EditSession `EditSession`]]s. * Contains the text of the document. Document can be attached to several [[EditSession `EditSession`]]s.
*
* At its core, `Document`s are just an array of strings, with each row in the document matching up to the array index. * At its core, `Document`s are just an array of strings, with each row in the document matching up to the array index.
* *
* @class Document * @class Document
**/ **/
/** /**
* *
* Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty. * Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty.
* @param {String | Array} text The starting text * @param {String | Array} text The starting text
* @constructor * @constructor
**/ **/
var Document = function(text) { var Document = function(textOrLines) {
this.$lines = []; this.$lines = [""];
// There has to be one line at least in the document. If you pass an empty // There has to be one line at least in the document. If you pass an empty
// string to the insert function, nothing will happen. Workaround. // string to the insert function, nothing will happen. Workaround.
if (text.length === 0) { if (textOrLines.length === 0) {
this.$lines = [""]; this.$lines = [""];
} else if (Array.isArray(text)) { } else if (Array.isArray(textOrLines)) {
this._insertLines(0, text); this.insertMergedLines({row: 0, column: 0}, textOrLines);
} else { } else {
this.insert({row: 0, column:0}, text); this.insert({row: 0, column:0}, textOrLines);
} }
}; };
@ -75,9 +75,9 @@ var Document = function(text) {
* @param {String} text The text to use * @param {String} text The text to use
**/ **/
this.setValue = function(text) { this.setValue = function(text) {
var len = this.getLength(); var len = this.getLength() - 1;
this.remove(new Range(0, 0, len, this.getLine(len-1).length)); this.remove(new Range(0, 0, len, this.getLine(len).length));
this.insert({row: 0, column:0}, text); this.insert({row: 0, column: 0}, text);
}; };
/** /**
@ -98,7 +98,7 @@ var Document = function(text) {
}; };
/** /**
* Splits a string of text on any newline (`\n`) or carriage-return ('\r') characters. * Splits a string of text on any newline (`\n`) or carriage-return (`\r`) characters.
* *
* @method $split * @method $split
* @param {String} text The text to work with * @param {String} text The text to work with
@ -107,14 +107,15 @@ var Document = function(text) {
**/ **/
// check for IE split bug // check for IE split bug
if ("aaa".split(/a/).length === 0) if ("aaa".split(/a/).length === 0) {
this.$split = function(text) { this.$split = function(text) {
return text.replace(/\r\n|\r/g, "\n").split("\n"); return text.replace(/\r\n|\r/g, "\n").split("\n");
}; };
else } else {
this.$split = function(text) { this.$split = function(text) {
return text.split(/\r\n|\r|\n/); return text.split(/\r\n|\r|\n/);
}; };
}
this.$detectNewLine = function(text) { this.$detectNewLine = function(text) {
@ -207,32 +208,49 @@ var Document = function(text) {
}; };
/** /**
* [Given a range within the document, this function returns all the text within that range as a single string.]{: #Document.getTextRange.desc} * Returns all the text within `range` as a single string.
* @param {Range} range The range to work with * @param {Range} range The range to work with.
* *
* @returns {String} * @returns {String}
**/ **/
this.getTextRange = function(range) { this.getTextRange = function(range) {
if (range.start.row == range.end.row) { return this.getLinesForRange(range).join(this.getNewLineCharacter());
return this.getLine(range.start.row) };
.substring(range.start.column, range.end.column);
/**
* Returns all the text within `range` as an array of lines.
* @param {Range} range The range to work with.
*
* @returns {Array}
**/
this.getLinesForRange = function(range) {
var lines;
if (range.start.row === range.end.row) {
// Handle a single-line range.
lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)];
} else {
// Handle a multi-line range.
lines = this.getLines(range.start.row, range.end.row);
lines[0] = (lines[0] || "").substring(range.start.column);
var l = lines.length - 1;
if (range.end.row - range.start.row == l)
lines[l] = lines[l].substring(0, range.end.column);
} }
var lines = this.getLines(range.start.row, range.end.row); return lines;
lines[0] = (lines[0] || "").substring(range.start.column);
var l = lines.length - 1;
if (range.end.row - range.start.row == l)
lines[l] = lines[l].substring(0, range.end.column);
return lines.join(this.getNewLineCharacter());
}; };
this.$clipPosition = function(position) { // Deprecated methods retained for backwards compatibility.
var length = this.getLength(); this.insertLines = function(row, lines) {
if (position.row >= length) { console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead.");
position.row = Math.max(0, length - 1); return this.insertFullLines(row, lines);
position.column = this.getLine(length-1).length; };
} else if (position.row < 0) this.removeLines = function(firstRow, lastRow) {
position.row = 0; console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead.");
return position; return this.removeFullLines(firstRow, lastRow);
};
this.insertNewLine = function(position) {
console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\'\', \'\']) instead.");
return this.insertMergedLines(position, ["", ""]);
}; };
/** /**
@ -243,53 +261,97 @@ var Document = function(text) {
* *
**/ **/
this.insert = function(position, text) { this.insert = function(position, text) {
if (!text || text.length === 0) // Only detect new lines if the document has no line break yet.
return position;
position = this.$clipPosition(position);
// only detect new lines if the document has no line break yet
if (this.getLength() <= 1) if (this.getLength() <= 1)
this.$detectNewLine(text); this.$detectNewLine(text);
var lines = this.$split(text); return this.insertMergedLines(position, this.$split(text));
var firstLine = lines.splice(0, 1)[0]; };
var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0];
/**
position = this.insertInLine(position, firstLine); * Inserts `text` into the `position` at the current row. This method also triggers the `"change"` event.
if (lastLine !== null) { *
position = this.insertNewLine(position); // terminate first line * This differs from the `insert` method in two ways:
position = this._insertLines(position.row, lines); * 1. This does NOT handle newline characters (single-line text only).
position = this.insertInLine(position, lastLine || ""); * 2. This is faster than the `insert` method for single-line text insertions.
*
* @param {Object} position The position to insert at; it's an object that looks like `{ row: row, column: column}`
* @param {String} text A chunk of text
* @returns {Object} Returns an object containing the final row and column, like this:
* ```
* {row: endRow, column: 0}
* ```
**/
this.insertInLine = function(position, text) {
var start = this.clippedPos(position.row, position.column);
var end = this.pos(position.row, position.column + text.length);
this.applyDelta({
start: start,
end: end,
action: "insert",
lines: [text]
}, true);
return this.clonePos(end);
};
this.clippedPos = function(row, column) {
var length = this.getLength();
if (row === undefined) {
row = length;
} else if (row < 0) {
row = 0;
} else if (row >= length) {
row = length - 1;
column = undefined;
}
var line = this.getLine(row);
if (column == undefined)
column = line.length;
column = Math.min(Math.max(column, 0), line.length);
return {row: row, column: column};
};
this.clonePos = function(pos) {
return {row: pos.row, column: pos.column};
};
this.pos = function(row, column) {
return {row: row, column: column};
};
this.$clipPosition = function(position) {
var length = this.getLength();
if (position.row >= length) {
position.row = Math.max(0, length - 1);
position.column = this.getLine(length - 1).length;
} else {
position.row = Math.max(0, position.row);
position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length);
} }
return position; return position;
}; };
/** /**
* Fires whenever the document changes. * Fires whenever the document changes.
* *
* Several methods trigger different `"change"` events. Below is a list of each action type, followed by each property that's also available: * Several methods trigger different `"change"` events. Below is a list of each action type, followed by each property that's also available:
* *
* * `"insertLines"` (emitted by [[Document.insertLines]]) * * `"insert"`
* * `range`: the [[Range]] of the change within the document * * `range`: the [[Range]] of the change within the document
* * `lines`: the lines in the document that are changing * * `lines`: the lines being added
* * `"insertText"` (emitted by [[Document.insertNewLine]]) * * `"remove"`
* * `range`: the [[Range]] of the change within the document * * `range`: the [[Range]] of the change within the document
* * `text`: the text that's being added * * `lines`: the lines being removed
* * `"removeLines"` (emitted by [[Document.insertLines]]) *
* * `range`: the [[Range]] of the change within the document * @event change
* * `lines`: the lines in the document that were removed * @param {Object} e Contains at least one property called `"action"`. `"action"` indicates the action that triggered the change. Each action also has a set of additional properties.
* * `nl`: the new line character (as defined by [[Document.getNewLineCharacter]]) *
* * `"removeText"` (emitted by [[Document.removeInLine]] and [[Document.removeNewLine]]) **/
* * `range`: the [[Range]] of the change within the document
* * `text`: the text that's being removed
*
* @event change
* @param {Object} e Contains at least one property called `"action"`. `"action"` indicates the action that triggered the change. Each action also has a set of additional properties.
*
**/
/** /**
* Inserts the elements in `lines` into the document, starting at the row index given by `row`. This method also triggers the `'change'` event. * Inserts the elements in `lines` into the document as full lines (does not merge with existing line), starting at the row index given by `row`. This method also triggers the `"change"` event.
* @param {Number} row The index of the row to insert at * @param {Number} row The index of the row to insert at
* @param {Array} lines An array of strings * @param {Array} lines An array of strings
* @returns {Object} Contains the final row and column, like this: * @returns {Object} Contains the final row and column, like this:
@ -302,100 +364,57 @@ var Document = function(text) {
* ``` * ```
* *
**/ **/
this.insertLines = function(row, lines) { this.insertFullLines = function(row, lines) {
if (row >= this.getLength()) // Clip to document.
return this.insert({row: row, column: 0}, "\n" + lines.join("\n")); // Allow one past the document end.
return this._insertLines(Math.max(row, 0), lines); row = Math.min(Math.max(row, 0), this.getLength());
};
this._insertLines = function(row, lines) { // Calculate insertion point.
if (lines.length == 0) var column = 0;
return {row: row, column: 0}; if (row < this.getLength()) {
// Insert before the specified row.
// apply doesn't work for big arrays (smallest threshold is on safari 0xFFFF) lines = lines.concat([""]);
// to circumvent that we have to break huge inserts into smaller chunks here column = 0;
while (lines.length > 0xF000) { } else {
var end = this._insertLines(row, lines.slice(0, 0xF000)); // Insert after the last row in the document.
lines = lines.slice(0xF000); lines = [""].concat(lines);
row = end.row; row--;
column = this.$lines[row].length;
} }
// Insert.
this.insertMergedLines({row: row, column: column}, lines);
};
var args = [row, 0]; /**
args.push.apply(args, lines); * Inserts the elements in `lines` into the document, starting at the position index given by `row`. This method also triggers the `"change"` event.
this.$lines.splice.apply(this.$lines, args); * @param {Number} row The index of the row to insert at
* @param {Array} lines An array of strings
var range = new Range(row, 0, row + lines.length, 0); * @returns {Object} Contains the final row and column, like this:
var delta = { * ```
action: "insertLines", * {row: endRow, column: 0}
range: range, * ```
* If `lines` is empty, this function returns an object containing the current row, and column, like this:
* ```
* {row: row, column: 0}
* ```
*
**/
this.insertMergedLines = function(position, lines) {
var start = this.clippedPos(position.row, position.column);
var end = {
row: start.row + lines.length - 1,
column: (lines.length == 1 ? start.column : 0) + lines[lines.length - 1].length
};
this.applyDelta({
start: start,
end: end,
action: "insert",
lines: lines lines: lines
}; });
this._signal("change", { data: delta });
return range.end; return this.clonePos(end);
};
/**
* Inserts a new line into the document at the current row's `position`. This method also triggers the `'change'` event.
* @param {Object} position The position to insert at
* @returns {Object} Returns an object containing the final row and column, like this:<br/>
* ```
* {row: endRow, column: 0}
* ```
*
**/
this.insertNewLine = function(position) {
position = this.$clipPosition(position);
var line = this.$lines[position.row] || "";
this.$lines[position.row] = line.substring(0, position.column);
this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));
var end = {
row : position.row + 1,
column : 0
};
var delta = {
action: "insertText",
range: Range.fromPoints(position, end),
text: this.getNewLineCharacter()
};
this._signal("change", { data: delta });
return end;
};
/**
* Inserts `text` into the `position` at the current row. This method also triggers the `'change'` event.
* @param {Object} position The position to insert at; it's an object that looks like `{ row: row, column: column}`
* @param {String} text A chunk of text
* @returns {Object} Returns an object containing the final row and column, like this:
* ```
* {row: endRow, column: 0}
* ```
*
**/
this.insertInLine = function(position, text) {
if (text.length == 0)
return position;
var line = this.$lines[position.row] || "";
this.$lines[position.row] = line.substring(0, position.column) + text
+ line.substring(position.column);
var end = {
row : position.row,
column : position.column + text.length
};
var delta = {
action: "insertText",
range: Range.fromPoints(position, end),
text: text
};
this._signal("change", { data: delta });
return end;
}; };
/** /**
@ -405,113 +424,90 @@ var Document = function(text) {
* *
**/ **/
this.remove = function(range) { this.remove = function(range) {
if (!(range instanceof Range)) var start = this.clippedPos(range.start.row, range.start.column);
range = Range.fromPoints(range.start, range.end); var end = this.clippedPos(range.end.row, range.end.column);
// clip to document this.applyDelta({
range.start = this.$clipPosition(range.start); start: start,
range.end = this.$clipPosition(range.end); end: end,
action: "remove",
if (range.isEmpty()) lines: this.getLinesForRange({start: start, end: end})
return range.start; });
return this.clonePos(start);
var firstRow = range.start.row;
var lastRow = range.end.row;
if (range.isMultiLine()) {
var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
var lastFullRow = lastRow - 1;
if (range.end.column > 0)
this.removeInLine(lastRow, 0, range.end.column);
if (lastFullRow >= firstFullRow)
this._removeLines(firstFullRow, lastFullRow);
if (firstFullRow != firstRow) {
this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length);
this.removeNewLine(range.start.row);
}
}
else {
this.removeInLine(firstRow, range.start.column, range.end.column);
}
return range.start;
}; };
/** /**
* Removes the specified columns from the `row`. This method also triggers the `'change'` event. * Removes the specified columns from the `row`. This method also triggers a `"change"` event.
* @param {Number} row The row to remove from * @param {Number} row The row to remove from
* @param {Number} startColumn The column to start removing at * @param {Number} startColumn The column to start removing at
* @param {Number} endColumn The column to stop removing at * @param {Number} endColumn The column to stop removing at
* @returns {Object} Returns an object containing `startRow` and `startColumn`, indicating the new row and column values.<br/>If `startColumn` is equal to `endColumn`, this function returns nothing. * @returns {Object} Returns an object containing `startRow` and `startColumn`, indicating the new row and column values.<br/>If `startColumn` is equal to `endColumn`, this function returns nothing.
* *
**/ **/
this.removeInLine = function(row, startColumn, endColumn) { this.removeInLine = function(row, startColumn, endColumn) {
if (startColumn == endColumn) var start = this.clippedPos(row, startColumn);
return; var end = this.clippedPos(row, endColumn);
var range = new Range(row, startColumn, row, endColumn); this.applyDelta({
var line = this.getLine(row); start: start,
var removed = line.substring(startColumn, endColumn); end: end,
var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length); action: "remove",
this.$lines.splice(row, 1, newLine); lines: this.getLinesForRange({start: start, end: end})
}, true);
var delta = {
action: "removeText", return this.clonePos(start);
range: range,
text: removed
};
this._signal("change", { data: delta });
return range.start;
}; };
/** /**
* Removes a range of full lines. This method also triggers the `'change'` event. * Removes a range of full lines. This method also triggers the `"change"` event.
* @param {Number} firstRow The first row to be removed * @param {Number} firstRow The first row to be removed
* @param {Number} lastRow The last row to be removed * @param {Number} lastRow The last row to be removed
* @returns {[String]} Returns all the removed lines. * @returns {[String]} Returns all the removed lines.
* *
**/ **/
this.removeLines = function(firstRow, lastRow) { this.removeFullLines = function(firstRow, lastRow) {
if (firstRow < 0 || lastRow >= this.getLength()) // Clip to document.
return this.remove(new Range(firstRow, 0, lastRow + 1, 0)); firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1);
return this._removeLines(firstRow, lastRow); lastRow = Math.min(Math.max(0, lastRow ), this.getLength() - 1);
};
// Calculate deletion range.
this._removeLines = function(firstRow, lastRow) { // Delete the ending new line unless we're at the end of the document.
var range = new Range(firstRow, 0, lastRow + 1, 0); // If we're at the end of the document, delete the starting new line.
var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1); var deleteFirstNewLine = lastRow == this.getLength() - 1 && firstRow > 0;
var deleteLastNewLine = lastRow < this.getLength() - 1;
var delta = { var startRow = ( deleteFirstNewLine ? firstRow - 1 : firstRow );
action: "removeLines", var startCol = ( deleteFirstNewLine ? this.getLine(startRow).length : 0 );
range: range, var endRow = ( deleteLastNewLine ? lastRow + 1 : lastRow );
nl: this.getNewLineCharacter(), var endCol = ( deleteLastNewLine ? 0 : this.getLine(endRow).length );
lines: removed var range = new Range(startRow, startCol, endRow, endCol);
};
this._signal("change", { data: delta }); // Store delelted lines with bounding newlines ommitted (maintains previous behavior).
return removed; var deletedLines = this.$lines.slice(firstRow, lastRow + 1);
this.applyDelta({
start: range.start,
end: range.end,
action: "remove",
lines: this.getLinesForRange(range)
});
// Return the deleted lines.
return deletedLines;
}; };
/** /**
* Removes the new line between `row` and the row immediately following it. This method also triggers the `'change'` event. * Removes the new line between `row` and the row immediately following it. This method also triggers the `"change"` event.
* @param {Number} row The row to check * @param {Number} row The row to check
* *
**/ **/
this.removeNewLine = function(row) { this.removeNewLine = function(row) {
var firstLine = this.getLine(row); if (row < this.getLength() - 1 && row >= 0) {
var secondLine = this.getLine(row+1); this.applyDelta({
start: this.pos(row, this.getLine(row).length),
var range = new Range(row, firstLine.length, row+1, 0); end: this.pos(row + 1, 0),
var line = firstLine + secondLine; action: "remove",
lines: ["", ""]
this.$lines.splice(row, 2, line); });
}
var delta = {
action: "removeText",
range: range,
text: this.getNewLineCharacter()
};
this._signal("change", { data: delta });
}; };
/** /**
@ -525,9 +521,9 @@ var Document = function(text) {
* *
**/ **/
this.replace = function(range, text) { this.replace = function(range, text) {
if (!(range instanceof Range)) if (!range instanceof Range)
range = Range.fromPoints(range.start, range.end); range = Range.fromPoints(range.start, range.end);
if (text.length == 0 && range.isEmpty()) if (text.length === 0 && range.isEmpty())
return range.start; return range.start;
// Shortcut: If the text we want to insert is the same as it is already // Shortcut: If the text we want to insert is the same as it is already
@ -536,55 +532,106 @@ var Document = function(text) {
return range.end; return range.end;
this.remove(range); this.remove(range);
var end;
if (text) { if (text) {
var end = this.insert(range.start, text); end = this.insert(range.start, text);
} }
else { else {
end = range.start; end = range.start;
} }
return end; return end;
}; };
/** /**
* Applies all the changes previously accumulated. These can be either `'insertText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`. * Applies all changes in `deltas` to the document.
* @param {Array} deltas An array of delta objects (can include "insert" and "remove" actions)
**/ **/
this.applyDeltas = function(deltas) { this.applyDeltas = function(deltas) {
for (var i=0; i<deltas.length; i++) { for (var i=0; i<deltas.length; i++) {
var delta = deltas[i]; this.applyDelta(deltas[i]);
var range = Range.fromPoints(delta.range.start, delta.range.end);
if (delta.action == "insertLines")
this.insertLines(range.start.row, delta.lines);
else if (delta.action == "insertText")
this.insert(range.start, delta.text);
else if (delta.action == "removeLines")
this._removeLines(range.start.row, range.end.row - 1);
else if (delta.action == "removeText")
this.remove(range);
} }
}; };
/** /**
* Reverts any changes previously applied. These can be either `'insertText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`. * Reverts all changes in `deltas` from the document.
* @param {Array} deltas An array of delta objects (can include "insert" and "remove" actions)
**/ **/
this.revertDeltas = function(deltas) { this.revertDeltas = function(deltas) {
for (var i=deltas.length-1; i>=0; i--) { for (var i=deltas.length-1; i>=0; i--) {
var delta = deltas[i]; this.revertDelta(deltas[i]);
var range = Range.fromPoints(delta.range.start, delta.range.end);
if (delta.action == "insertLines")
this._removeLines(range.start.row, range.end.row - 1);
else if (delta.action == "insertText")
this.remove(range);
else if (delta.action == "removeLines")
this._insertLines(range.start.row, delta.lines);
else if (delta.action == "removeText")
this.insert(range.start, delta.text);
} }
}; };
/**
* Applies `delta` to the document.
* @param {Object} delta A delta object (can include "insert" and "remove" actions)
**/
this.applyDelta = function(delta, doNotValidate) {
var isInsert = delta.action == "insert";
// An empty range is a NOOP.
if (isInsert ? delta.lines.length <= 1 && !delta.lines[0]
: !Range.comparePoints(delta.start, delta.end)) {
return;
}
if (isInsert && delta.lines.length > 20000)
this.$splitAndapplyLargeDelta(delta, 20000);
// Apply.
applyDelta(this.$lines, delta, doNotValidate);
this._signal("change", delta);
};
this.$splitAndapplyLargeDelta = function(delta, MAX) {
// Split large insert deltas. This is necessary because:
// 1. We need to support splicing delta lines into the document via $lines.splice.apply(...)
// 2. fn.apply() doesn't work for a large number of params. The smallest threshold is on chrome 40 ~42000.
// we use 20000 to leave some space for actual stack
//
// To Do: Ideally we'd be consistent and also split 'delete' deltas. We don't do this now, because delete
// delta handling is too slow. If we make delete delta handling faster we can split all large deltas
// as shown in https://gist.github.com/aldendaniels/8367109#file-document-snippet-js
// If we do this, update validateDelta() to limit the number of lines in a delete delta.
var lines = delta.lines;
var l = lines.length;
var row = delta.start.row;
var column = delta.start.column;
var from = 0, to = 0;
do {
from = to;
to += MAX - 1;
var chunk = lines.slice(from, to);
if (to > l) {
// Update remaining delta.
delta.lines = chunk;
delta.start.row = row + from;
delta.start.column = column;
break;
}
chunk.push("");
this.applyDelta({
start: this.pos(row + from, column),
end: this.pos(row + to, column = 0),
action: delta.action,
lines: chunk
}, true);
} while(true);
};
/**
* Reverts `delta` from the document.
* @param {Object} delta A delta object (can include "insert" and "remove" actions)
**/
this.revertDelta = function(delta) {
this.applyDelta({
start: this.clonePos(delta.start),
end: this.clonePos(delta.end),
action: (delta.action == "insert" ? "remove" : "insert"),
lines: delta.lines.slice()
});
};
/** /**
* Converts an index position in a document to a `{row, column}` object. * Converts an index position in a document to a `{row, column}` object.
* *

View file

@ -46,7 +46,7 @@ module.exports = {
var doc = new Document(["12", "34"]); var doc = new Document(["12", "34"]);
var deltas = []; var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); }); doc.on("change", function(e) { deltas.push(e); });
doc.insert({row: 0, column: 1}, "juhu"); doc.insert({row: 0, column: 1}, "juhu");
assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n")); assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n"));
@ -63,9 +63,9 @@ module.exports = {
var doc = new Document(["12", "34"]); var doc = new Document(["12", "34"]);
var deltas = []; var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); }); doc.on("change", function(e) { deltas.push(e); });
doc.insertNewLine({row: 0, column: 1}); doc.insertMergedLines({row: 0, column: 1}, ['', '']);
assert.equal(doc.getValue(), ["1", "2", "34"].join("\n")); assert.equal(doc.getValue(), ["1", "2", "34"].join("\n"));
var d = deltas.concat(); var d = deltas.concat();
@ -80,9 +80,9 @@ module.exports = {
var doc = new Document(["12", "34"]); var doc = new Document(["12", "34"]);
var deltas = []; var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); }); doc.on("change", function(e) { deltas.push(e); });
doc.insertLines(0, ["aa", "bb"]); doc.insertFullLines(0, ["aa", "bb"]);
assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n")); assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n"));
var d = deltas.concat(); var d = deltas.concat();
@ -97,9 +97,9 @@ module.exports = {
var doc = new Document(["12", "34"]); var doc = new Document(["12", "34"]);
var deltas = []; var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); }); doc.on("change", function(e) { deltas.push(e); });
doc.insertLines(2, ["aa", "bb"]); doc.insertFullLines(2, ["aa", "bb"]);
assert.equal(doc.getValue(), ["12", "34", "aa", "bb"].join("\n")); assert.equal(doc.getValue(), ["12", "34", "aa", "bb"].join("\n"));
}, },
@ -107,9 +107,9 @@ module.exports = {
var doc = new Document(["12", "34"]); var doc = new Document(["12", "34"]);
var deltas = []; var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); }); doc.on("change", function(e) { deltas.push(e); });
doc.insertLines(1, ["aa", "bb"]); doc.insertFullLines(1, ["aa", "bb"]);
assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n")); assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n"));
var d = deltas.concat(); var d = deltas.concat();
@ -124,7 +124,7 @@ module.exports = {
var doc = new Document(["12", "34"]); var doc = new Document(["12", "34"]);
var deltas = []; var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); }); doc.on("change", function(e) { deltas.push(e); });
doc.insert({row: 0, column: 0}, "aa\nbb\ncc"); doc.insert({row: 0, column: 0}, "aa\nbb\ncc");
assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n")); assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n"));
@ -141,9 +141,9 @@ module.exports = {
var doc = new Document(["12", "34"]); var doc = new Document(["12", "34"]);
var deltas = []; var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); }); doc.on("change", function(e) { deltas.push(e); });
doc.insert({row: 2, column: 0}, "aa\nbb\ncc"); doc.insert({row: 1, column: 2}, "aa\nbb\ncc");
assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n")); assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n"));
var d = deltas.concat(); var d = deltas.concat();
@ -158,7 +158,7 @@ module.exports = {
var doc = new Document(["12", "34"]); var doc = new Document(["12", "34"]);
var deltas = []; var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); }); doc.on("change", function(e) { deltas.push(e); });
doc.insert({row: 0, column: 1}, "aa\nbb\ncc"); doc.insert({row: 0, column: 1}, "aa\nbb\ncc");
assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n")); assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n"));
@ -175,7 +175,7 @@ module.exports = {
var doc = new Document(["1234", "5678"]); var doc = new Document(["1234", "5678"]);
var deltas = []; var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); }); doc.on("change", function(e) { deltas.push(e); });
doc.remove(new Range(0, 1, 0, 3)); doc.remove(new Range(0, 1, 0, 3));
assert.equal(doc.getValue(), ["14", "5678"].join("\n")); assert.equal(doc.getValue(), ["14", "5678"].join("\n"));
@ -192,7 +192,7 @@ module.exports = {
var doc = new Document(["1234", "5678"]); var doc = new Document(["1234", "5678"]);
var deltas = []; var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); }); doc.on("change", function(e) { deltas.push(e); });
doc.remove(new Range(0, 4, 1, 0)); doc.remove(new Range(0, 4, 1, 0));
assert.equal(doc.getValue(), ["12345678"].join("\n")); assert.equal(doc.getValue(), ["12345678"].join("\n"));
@ -209,7 +209,7 @@ module.exports = {
var doc = new Document(["1234", "5678", "abcd"]); var doc = new Document(["1234", "5678", "abcd"]);
var deltas = []; var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); }); doc.on("change", function(e) { deltas.push(e); });
doc.remove(new Range(0, 2, 2, 2)); doc.remove(new Range(0, 2, 2, 2));
assert.equal(doc.getValue(), ["12cd"].join("\n")); assert.equal(doc.getValue(), ["12cd"].join("\n"));
@ -226,7 +226,7 @@ module.exports = {
var doc = new Document(["1234", "5678", "abcd"]); var doc = new Document(["1234", "5678", "abcd"]);
var deltas = []; var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); }); doc.on("change", function(e) { deltas.push(e); });
doc.remove(new Range(1, 0, 3, 0)); doc.remove(new Range(1, 0, 3, 0));
assert.equal(doc.getValue(), ["1234", ""].join("\n")); assert.equal(doc.getValue(), ["1234", ""].join("\n"));
@ -235,7 +235,7 @@ module.exports = {
"test: remove lines should return the removed lines" : function() { "test: remove lines should return the removed lines" : function() {
var doc = new Document(["1234", "5678", "abcd"]); var doc = new Document(["1234", "5678", "abcd"]);
var removed = doc.removeLines(1, 2); var removed = doc.removeFullLines(1, 2);
assert.equal(removed.join("\n"), ["5678", "abcd"].join("\n")); assert.equal(removed.join("\n"), ["5678", "abcd"].join("\n"));
}, },
@ -296,6 +296,35 @@ module.exports = {
"test: empty document has to contain one line": function() { "test: empty document has to contain one line": function() {
var doc = new Document(""); var doc = new Document("");
assert.equal(doc.$lines.length, 1); assert.equal(doc.$lines.length, 1);
},
"test: ignore empty delta": function() {
var doc = new Document("");
doc.on("change", function() {
throw "should ignore empty delta";
})
doc.insert({row: 0, column: 0}, "");
doc.insert({row: 1, column: 1}, "");
doc.remove({start: {row: 1, column: 1}, end: {row: 1, column: 1}});
},
"test: inserting huge delta": function() {
var doc = new Document("");
var val = "";
var MAX = 0xF000;
for (var i = 0; i < 10 * MAX; i++) {
val += i + "\n"
}
doc.setValue(val);
assert.equal(doc.getValue(), val);
for (var i = 3 * MAX + 2; i >= 3 * MAX - 2; i--) {
val = doc.getLines(0, i).join("\n");
doc.setValue("\nab");
assert.equal(doc.getValue(), "\nab");
doc.insert({row: 1, column: 1}, val);
assert.equal(doc.getValue(), "\na" + val + "b");
}
} }
}; };

View file

@ -151,7 +151,7 @@ var EditSession = function(text, mode) {
this.$foldData = []; this.$foldData = [];
this.$foldData.toString = function() { this.$foldData.toString = function() {
return this.join("\n"); return this.join("\n");
} };
this.on("changeFold", this.onChangeFold.bind(this)); this.on("changeFold", this.onChangeFold.bind(this));
this.$onChange = this.onChange.bind(this); this.$onChange = this.onChange.bind(this);
@ -249,13 +249,12 @@ var EditSession = function(text, mode) {
this.$resetRowCache(fold.start.row); this.$resetRowCache(fold.start.row);
}; };
this.onChange = function(e) { this.onChange = function(delta) {
var delta = e.data;
this.$modified = true; this.$modified = true;
this.$resetRowCache(delta.range.start.row); this.$resetRowCache(delta.start.row);
var removedFolds = this.$updateInternalDataOnChange(e); var removedFolds = this.$updateInternalDataOnChange(delta);
if (!this.$fromUndo && this.$undoManager && !delta.ignore) { if (!this.$fromUndo && this.$undoManager && !delta.ignore) {
this.$deltasDoc.push(delta); this.$deltasDoc.push(delta);
if (removedFolds && removedFolds.length != 0) { if (removedFolds && removedFolds.length != 0) {
@ -269,7 +268,7 @@ var EditSession = function(text, mode) {
} }
this.bgTokenizer && this.bgTokenizer.$updateOnChange(delta); this.bgTokenizer && this.bgTokenizer.$updateOnChange(delta);
this._signal("change", e); this._signal("change", delta);
}; };
/** /**
@ -679,10 +678,10 @@ var EditSession = function(text, mode) {
}; };
/** /**
* Returns an array containing the IDs of all the markers, either front or back. * Returns an object containing all of the markers, either front or back.
* @param {Boolean} inFront If `true`, indicates you only want front markers; `false` indicates only back markers * @param {Boolean} inFront If `true`, indicates you only want front markers; `false` indicates only back markers
* *
* @returns {Array} * @returns {Object}
**/ **/
this.getMarkers = function(inFront) { this.getMarkers = function(inFront) {
return inFront ? this.$frontMarkers : this.$backMarkers; return inFront ? this.$frontMarkers : this.$backMarkers;
@ -1146,6 +1145,19 @@ var EditSession = function(text, mode) {
this.remove = function(range) { this.remove = function(range) {
return this.doc.remove(range); return this.doc.remove(range);
}; };
/**
* Removes a range of full lines. This method also triggers the `'change'` event.
* @param {Number} firstRow The first row to be removed
* @param {Number} lastRow The last row to be removed
* @returns {[String]} Returns all the removed lines.
*
* @related Document.removeFullLines
*
**/
this.removeFullLines = function(firstRow, lastRow){
return this.doc.removeFullLines(firstRow, lastRow);
};
/** /**
* Reverts previous changes to your document. * Reverts previous changes to your document.
@ -1222,39 +1234,36 @@ var EditSession = function(text, mode) {
this.$getUndoSelection = function(deltas, isUndo, lastUndoRange) { this.$getUndoSelection = function(deltas, isUndo, lastUndoRange) {
function isInsert(delta) { function isInsert(delta) {
var insert = return isUndo ? delta.action !== "insert" : delta.action === "insert";
delta.action === "insertText" || delta.action === "insertLines";
return isUndo ? !insert : insert;
} }
var delta = deltas[0]; var delta = deltas[0];
var range, point; var range, point;
var lastDeltaIsInsert = false; var lastDeltaIsInsert = false;
if (isInsert(delta)) { if (isInsert(delta)) {
range = Range.fromPoints(delta.range.start, delta.range.end); range = Range.fromPoints(delta.start, delta.end);
lastDeltaIsInsert = true; lastDeltaIsInsert = true;
} else { } else {
range = Range.fromPoints(delta.range.start, delta.range.start); range = Range.fromPoints(delta.start, delta.start);
lastDeltaIsInsert = false; lastDeltaIsInsert = false;
} }
for (var i = 1; i < deltas.length; i++) { for (var i = 1; i < deltas.length; i++) {
delta = deltas[i]; delta = deltas[i];
if (isInsert(delta)) { if (isInsert(delta)) {
point = delta.range.start; point = delta.start;
if (range.compare(point.row, point.column) == -1) { if (range.compare(point.row, point.column) == -1) {
range.setStart(delta.range.start); range.setStart(point);
} }
point = delta.range.end; point = delta.end;
if (range.compare(point.row, point.column) == 1) { if (range.compare(point.row, point.column) == 1) {
range.setEnd(delta.range.end); range.setEnd(point);
} }
lastDeltaIsInsert = true; lastDeltaIsInsert = true;
} else { } else {
point = delta.range.start; point = delta.start;
if (range.compare(point.row, point.column) == -1) { if (range.compare(point.row, point.column) == -1) {
range = range = Range.fromPoints(delta.start, delta.start);
Range.fromPoints(delta.range.start, delta.range.start);
} }
lastDeltaIsInsert = false; lastDeltaIsInsert = false;
} }
@ -1368,7 +1377,7 @@ var EditSession = function(text, mode) {
this.indentRows = function(startRow, endRow, indentString) { this.indentRows = function(startRow, endRow, indentString) {
indentString = indentString.replace(/\t/g, this.getTabString()); indentString = indentString.replace(/\t/g, this.getTabString());
for (var row=startRow; row<=endRow; row++) for (var row=startRow; row<=endRow; row++)
this.insert({row: row, column:0}, indentString); this.doc.insertInLine({row: row, column: 0}, indentString);
}; };
/** /**
@ -1425,11 +1434,11 @@ var EditSession = function(text, mode) {
x.end.row += diff; x.end.row += diff;
return x; return x;
}); });
var lines = dir == 0 var lines = dir == 0
? this.doc.getLines(firstRow, lastRow) ? this.doc.getLines(firstRow, lastRow)
: this.doc.removeLines(firstRow, lastRow); : this.doc.removeFullLines(firstRow, lastRow);
this.doc.insertLines(firstRow+diff, lines); this.doc.insertFullLines(firstRow+diff, lines);
folds.length && this.addFolds(folds); folds.length && this.addFolds(folds);
return diff; return diff;
}; };
@ -1439,8 +1448,6 @@ var EditSession = function(text, mode) {
* @param {Number} lastRow The final row to move up * @param {Number} lastRow The final row to move up
* @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1. * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1.
* *
* @related Document.insertLines
*
**/ **/
this.moveLinesUp = function(firstRow, lastRow) { this.moveLinesUp = function(firstRow, lastRow) {
return this.$moveLines(firstRow, lastRow, -1); return this.$moveLines(firstRow, lastRow, -1);
@ -1451,8 +1458,6 @@ var EditSession = function(text, mode) {
* @param {Number} firstRow The starting row to move down * @param {Number} firstRow The starting row to move down
* @param {Number} lastRow The final row to move down * @param {Number} lastRow The final row to move down
* @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1. * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1.
*
* @related Document.insertLines
**/ **/
this.moveLinesDown = function(firstRow, lastRow) { this.moveLinesDown = function(firstRow, lastRow) {
return this.$moveLines(firstRow, lastRow, 1); return this.$moveLines(firstRow, lastRow, 1);
@ -1656,34 +1661,23 @@ var EditSession = function(text, mode) {
}; };
}; };
this.$updateInternalDataOnChange = function(e) { this.$updateInternalDataOnChange = function(delta) {
var useWrapMode = this.$useWrapMode; var useWrapMode = this.$useWrapMode;
var len; var action = delta.action;
var action = e.data.action; var start = delta.start;
var firstRow = e.data.range.start.row; var end = delta.end;
var lastRow = e.data.range.end.row; var firstRow = start.row;
var start = e.data.range.start; var lastRow = end.row;
var end = e.data.range.end; var len = lastRow - firstRow;
var removedFolds = null; var removedFolds = null;
if (action.indexOf("Lines") != -1) {
if (action == "insertLines") {
lastRow = firstRow + (e.data.lines.length);
} else {
lastRow = firstRow;
}
len = e.data.lines ? e.data.lines.length : lastRow - firstRow;
} else {
len = lastRow - firstRow;
}
this.$updating = true; this.$updating = true;
if (len != 0) { if (len != 0) {
if (action.indexOf("remove") != -1) { if (action === "remove") {
this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len); this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len);
var foldLines = this.$foldData; var foldLines = this.$foldData;
removedFolds = this.getFoldsInRange(e.data.range); removedFolds = this.getFoldsInRange(delta);
this.removeFolds(removedFolds); this.removeFolds(removedFolds);
var foldLine = this.getFoldLine(end.row); var foldLine = this.getFoldLine(end.row);
@ -1748,10 +1742,10 @@ var EditSession = function(text, mode) {
} else { } else {
// Realign folds. E.g. if you add some new chars before a fold, the // Realign folds. E.g. if you add some new chars before a fold, the
// fold should "move" to the right. // fold should "move" to the right.
len = Math.abs(e.data.range.start.column - e.data.range.end.column); len = Math.abs(delta.start.column - delta.end.column);
if (action.indexOf("remove") != -1) { if (action === "remove") {
// Get all the folds in the change range and remove them. // Get all the folds in the change range and remove them.
removedFolds = this.getFoldsInRange(e.data.range); removedFolds = this.getFoldsInRange(delta);
this.removeFolds(removedFolds); this.removeFolds(removedFolds);
len = -len; len = -len;
@ -1835,7 +1829,7 @@ var EditSession = function(text, mode) {
TAB_SPACE = 12; TAB_SPACE = 12;
this.$computeWrapSplits = function(tokens, wrapLimit) { this.$computeWrapSplits = function(tokens, wrapLimit, tabSize) {
if (tokens.length == 0) { if (tokens.length == 0) {
return []; return [];
} }
@ -1846,6 +1840,31 @@ var EditSession = function(text, mode) {
var isCode = this.$wrapAsCode; var isCode = this.$wrapAsCode;
var indentedSoftWrap = this.$indentedSoftWrap;
var maxIndent = wrapLimit <= Math.max(2 * tabSize, 8)
|| indentedSoftWrap === false ? 0 : Math.floor(wrapLimit / 2);
function getWrapIndent() {
var indentation = 0;
if (maxIndent === 0)
return indentation;
if (indentedSoftWrap) {
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
if (token == SPACE)
indentation += 1;
else if (token == TAB)
indentation += tabSize;
else if (token == TAB_SPACE)
continue;
else
break;
}
}
if (isCode && indentedSoftWrap !== false)
indentation += tabSize;
return Math.min(indentation, maxIndent);
}
function addSplit(screenPos) { function addSplit(screenPos) {
var displayed = tokens.slice(lastSplit, screenPos); var displayed = tokens.slice(lastSplit, screenPos);
@ -1862,14 +1881,18 @@ var EditSession = function(text, mode) {
len -= 1; len -= 1;
}); });
if (!splits.length) {
indent = getWrapIndent();
splits.indent = indent;
}
lastDocSplit += len; lastDocSplit += len;
splits.push(lastDocSplit); splits.push(lastDocSplit);
lastSplit = screenPos; lastSplit = screenPos;
} }
var indent = 0;
while (displayLength - lastSplit > wrapLimit) { while (displayLength - lastSplit > wrapLimit - indent) {
// This is, where the split should be. // This is, where the split should be.
var split = lastSplit + wrapLimit; var split = lastSplit + wrapLimit - indent;
// If there is a space or tab at this split position, then making // If there is a space or tab at this split position, then making
// a split is simple. // a split is simple.
@ -1929,7 +1952,7 @@ var EditSession = function(text, mode) {
// === ELSE === // === ELSE ===
// Search for the first non space/tab/placeholder/punctuation token backwards. // Search for the first non space/tab/placeholder/punctuation token backwards.
var minSplit = Math.max(split - (isCode ? 10 : wrapLimit-(wrapLimit>>2)), lastSplit - 1); var minSplit = Math.max(split - (wrapLimit -(wrapLimit>>2)), lastSplit - 1);
while (split > minSplit && tokens[split] < PLACEHOLDER_START) { while (split > minSplit && tokens[split] < PLACEHOLDER_START) {
split --; split --;
} }
@ -1957,7 +1980,7 @@ var EditSession = function(text, mode) {
// around -> force a split. // around -> force a split.
if (tokens[split] == CHAR_EXT) if (tokens[split] == CHAR_EXT)
split--; split--;
addSplit(split); addSplit(split - indent);
} }
return splits; return splits;
}; };
@ -2064,6 +2087,16 @@ var EditSession = function(text, mode) {
} }
}; };
this.getRowWrapIndent = function(screenRow) {
if (this.$useWrapMode) {
var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE);
var splits = this.$wrapData[pos.row];
return splits.length && splits[0] < pos.column ? splits.indent : 0;
} else {
return 0;
}
}
/** /**
* Returns the position (on screen) for the last character in the provided screen row. * Returns the position (on screen) for the last character in the provided screen row.
* @param {Number} screenRow The screen row to check * @param {Number} screenRow The screen row to check
@ -2201,20 +2234,21 @@ var EditSession = function(text, mode) {
line = this.getLine(docRow); line = this.getLine(docRow);
foldLine = null; foldLine = null;
} }
var wrapIndent = 0;
if (this.$useWrapMode) { if (this.$useWrapMode) {
var splits = this.$wrapData[docRow]; var splits = this.$wrapData[docRow];
if (splits) { if (splits) {
var splitIndex = Math.floor(screenRow - row); var splitIndex = Math.floor(screenRow - row);
column = splits[splitIndex]; column = splits[splitIndex];
if(splitIndex > 0 && splits.length) { if(splitIndex > 0 && splits.length) {
wrapIndent = splits.indent;
docColumn = splits[splitIndex - 1] || splits[splits.length - 1]; docColumn = splits[splitIndex - 1] || splits[splits.length - 1];
line = line.substring(docColumn); line = line.substring(docColumn);
} }
} }
} }
docColumn += this.$getStringScreenWidth(line, screenColumn)[1]; docColumn += this.$getStringScreenWidth(line, screenColumn - wrapIndent)[1];
// We remove one character at the end so that the docColumn // We remove one character at the end so that the docColumn
// position returned is not associated to the next row on the screen. // position returned is not associated to the next row on the screen.
@ -2306,6 +2340,7 @@ var EditSession = function(text, mode) {
textLine = this.getLine(docRow).substring(0, docColumn); textLine = this.getLine(docRow).substring(0, docColumn);
foldStartRow = docRow; foldStartRow = docRow;
} }
var wrapIndent = 0;
// Clamp textLine if in wrapMode. // Clamp textLine if in wrapMode.
if (this.$useWrapMode) { if (this.$useWrapMode) {
var wrapRow = this.$wrapData[foldStartRow]; var wrapRow = this.$wrapData[foldStartRow];
@ -2318,12 +2353,13 @@ var EditSession = function(text, mode) {
textLine = textLine.substring( textLine = textLine.substring(
wrapRow[screenRowOffset - 1] || 0, textLine.length wrapRow[screenRowOffset - 1] || 0, textLine.length
); );
wrapIndent = screenRowOffset > 0 ? wrapRow.indent : 0;
} }
} }
return { return {
row: screenRow, row: screenRow,
column: this.$getStringScreenWidth(textLine)[0] column: wrapIndent + this.$getStringScreenWidth(textLine)[0]
}; };
}; };
@ -2503,6 +2539,7 @@ config.defineOptions(EditSession.prototype, "session", {
}, },
initialValue: "auto" initialValue: "auto"
}, },
indentedSoftWrap: { initialValue: true },
firstLineNumber: { firstLineNumber: {
set: function() {this._signal("changeBreakpoint");}, set: function() {this._signal("changeBreakpoint");},
initialValue: 1 initialValue: 1

View file

@ -117,7 +117,7 @@ function BracketMatch() {
typeRe = new RegExp( typeRe = new RegExp(
"(\\.?" + "(\\.?" +
token.type.replace(".", "\\.").replace("rparen", ".paren") token.type.replace(".", "\\.").replace("rparen", ".paren")
.replace(/\b(?:end|start|begin)\b/, "") .replace(/\b(?:end)\b/, "(?:start|begin|end)")
+ ")+" + ")+"
); );
} }
@ -174,7 +174,7 @@ function BracketMatch() {
typeRe = new RegExp( typeRe = new RegExp(
"(\\.?" + "(\\.?" +
token.type.replace(".", "\\.").replace("lparen", ".paren") token.type.replace(".", "\\.").replace("lparen", ".paren")
.replace(/\b(?:end|start|begin)\b/, "") .replace(/\b(?:start|begin)\b/, "(?:start|begin|end)")
+ ")+" + ")+"
); );
} }

View file

@ -829,15 +829,13 @@ function Folding() {
} }
}; };
this.updateFoldWidgets = function(e) { this.updateFoldWidgets = function(delta) {
var delta = e.data; var firstRow = delta.start.row;
var range = delta.range; var len = delta.end.row - firstRow;
var firstRow = range.start.row;
var len = range.end.row - firstRow;
if (len === 0) { if (len === 0) {
this.foldWidgets[firstRow] = null; this.foldWidgets[firstRow] = null;
} else if (delta.action == "removeText" || delta.action == "removeLines") { } else if (delta.action == 'remove') {
this.foldWidgets.splice(firstRow, len + 1, null); this.foldWidgets.splice(firstRow, len + 1, null);
} else { } else {
var args = Array(len + 1); var args = Array(len + 1);

View file

@ -280,7 +280,7 @@ module.exports = {
session.setUseWrapMode(true); session.setUseWrapMode(true);
session.setWrapLimitRange(12, 12); session.setWrapLimitRange(12, 12);
session.adjustWrapLimit(80); session.adjustWrapLimit(80);
session.setOption("wrapMethod", "text");
assert.position(session.documentToScreenPosition(0, 11), 0, 11); assert.position(session.documentToScreenPosition(0, 11), 0, 11);
assert.position(session.documentToScreenPosition(0, 12), 1, 0); assert.position(session.documentToScreenPosition(0, 12), 1, 0);
}, },
@ -380,7 +380,8 @@ module.exports = {
line = lang.stringTrimRight(line); line = lang.stringTrimRight(line);
var tokens = EditSession.prototype.$getDisplayTokens(line); var tokens = EditSession.prototype.$getDisplayTokens(line);
var splits = EditSession.prototype.$computeWrapSplits(tokens, wrapLimit, tabSize); var splits = EditSession.prototype.$computeWrapSplits(tokens, wrapLimit, tabSize);
// console.log("String:", line, "Result:", splits, "Expected:", assertEqual); console.log("String:", line, "Result:", splits, "Expected:", assertEqual);
assert.ok(splits.length == assertEqual.length); assert.ok(splits.length == assertEqual.length);
for (var i = 0; i < splits.length; i++) { for (var i = 0; i < splits.length; i++) {
assert.ok(splits[i] == assertEqual[i]); assert.ok(splits[i] == assertEqual[i]);
@ -388,6 +389,7 @@ module.exports = {
} }
EditSession.prototype.$wrapAsCode = true; EditSession.prototype.$wrapAsCode = true;
EditSession.prototype.$indentedSoftWrap = false;
// Basic splitting. // Basic splitting.
computeAndAssert("foo bar foo bar", [ 12 ]); computeAndAssert("foo bar foo bar", [ 12 ]);
computeAndAssert("foo bar f bar", [ 12 ]); computeAndAssert("foo bar f bar", [ 12 ]);
@ -413,16 +415,26 @@ module.exports = {
computeAndAssert("ぁぁ", [1], 2); computeAndAssert("ぁぁ", [1], 2);
computeAndAssert(" ぁぁ", [1, 2], 2); computeAndAssert(" ぁぁ", [1, 2], 2);
computeAndAssert(" ぁ\tぁ", [1, 3], 2); computeAndAssert(" ぁ\tぁ", [1, 3], 2);
computeAndAssert(" ぁぁ\tぁ", [1, 4], 4); computeAndAssert(" ぁぁ\tぁ", [2, 4], 4);
computeAndAssert("ぁぁ ぁぁ\tぁ", [3, 6], 6);
// Test wrapping for punctuation. // Test wrapping for punctuation.
computeAndAssert(" ab.c;ef++", [1, 3, 5, 7, 8], 2); computeAndAssert(" ab.c;ef++", [2, 4, 6, 8], 2);
computeAndAssert(" ab.c;ef++", [3, 5, 8], 3);
computeAndAssert(" a.b", [1, 2, 3], 1); computeAndAssert(" a.b", [1, 2, 3], 1);
computeAndAssert("#>>", [1, 2], 1); computeAndAssert("#>>", [1, 2], 1);
// Test wrapping for punctuation in // Test wrapping for punctuation in
EditSession.prototype.$wrapAsCode = false; EditSession.prototype.$wrapAsCode = false;
computeAndAssert("ab cde, Juhu kinners", [3, 8, 13, 19], 6); computeAndAssert("ab cde, Juhu kinners", [3, 8, 13, 19], 6);
// test indented wrapping
EditSession.prototype.$indentedSoftWrap = true;
computeAndAssert("foo bar foo bar foo bara foo", [12, 25]);
computeAndAssert("fooooooooooooooooooooooooooo", [12, 24]);
computeAndAssert("\t\tfoo bar fooooooooooobooooooo", [6, 10, 16, 22, 28]);
computeAndAssert("\t\t\tfoo bar fooooooooooobooooooo", [3, 7, 11, 17, 23, 29]);
computeAndAssert("\tfoo \t \t \t \t bar", [6, 12]); // 14
}, },
"test get longest line" : function() { "test get longest line" : function() {
@ -430,12 +442,12 @@ module.exports = {
session.setTabSize(4); session.setTabSize(4);
assert.equal(session.getScreenWidth(), 2); assert.equal(session.getScreenWidth(), 2);
session.doc.insertNewLine({row: 0, column: Infinity}); session.doc.insertMergedLines({row: 0, column: Infinity}, ['', '']);
session.doc.insertLines(1, ["123"]); session.doc.insertFullLines(1, ["123"]);
assert.equal(session.getScreenWidth(), 3); assert.equal(session.getScreenWidth(), 3);
session.doc.insertNewLine({row: 0, column: Infinity}); session.doc.insertMergedLines({row: 0, column: Infinity}, ['', '']);
session.doc.insertLines(1, ["\t\t"]); session.doc.insertFullLines(1, ["\t\t"]);
assert.equal(session.getScreenWidth(), 8); assert.equal(session.getScreenWidth(), 8);
@ -459,9 +471,9 @@ module.exports = {
session.setUseWrapMode(true); session.setUseWrapMode(true);
document.insertLines(0, ["a", "b"]); document.insertFullLines(0, ["a", "b"]);
document.insertLines(2, ["c", "d"]); document.insertFullLines(2, ["c", "d"]);
document.removeLines(1, 2); document.removeFullLines(1, 2);
}, },
"test wrapMode init has to create wrapData array": function() { "test wrapMode init has to create wrapData array": function() {

View file

@ -150,9 +150,8 @@ var Editor = function(renderer, session) {
args: commadEvent.args, args: commadEvent.args,
scrollTop: this.renderer.scrollTop scrollTop: this.renderer.scrollTop
}; };
if (this.curOp.command.name) if (this.curOp.command.name && this.curOp.command.scrollIntoView !== undefined)
this.$blockScrolling++; this.$blockScrolling++;
// this.selections.push(this.selection.toJSON());
}; };
this.endOperation = function(e) { this.endOperation = function(e) {
@ -161,10 +160,14 @@ var Editor = function(renderer, session) {
return this.curOp = null; return this.curOp = null;
this._signal("beforeEndOperation"); this._signal("beforeEndOperation");
var command = this.curOp.command; var command = this.curOp.command;
if (command.name && this.$blockScrolling) if (command.name && this.$blockScrolling > 0)
this.$blockScrolling--; this.$blockScrolling--;
if (command && command.scrollIntoView) { var scrollIntoView = command && command.scrollIntoView;
switch (command.scrollIntoView) { if (scrollIntoView) {
switch (scrollIntoView) {
case "center-animate":
scrollIntoView = "animate";
/* fall through */
case "center": case "center":
this.renderer.scrollCursorIntoView(null, 0.5); this.renderer.scrollCursorIntoView(null, 0.5);
break; break;
@ -182,7 +185,7 @@ var Editor = function(renderer, session) {
default: default:
break; break;
} }
if (command.scrollIntoView == "animate") if (scrollIntoView == "animate")
this.renderer.animateScrolling(this.curOp.scrollTop); this.renderer.animateScrolling(this.curOp.scrollTop);
} }
@ -275,6 +278,10 @@ var Editor = function(renderer, session) {
this.setSession = function(session) { this.setSession = function(session) {
if (this.session == session) if (this.session == session)
return; return;
// make sure operationEnd events are not emitted to wrong session
if (this.curOp) this.endOperation();
this.curOp = {};
var oldSession = this.session; var oldSession = this.session;
if (oldSession) { if (oldSession) {
@ -374,6 +381,8 @@ var Editor = function(renderer, session) {
oldSession: oldSession oldSession: oldSession
}); });
this.curOp = null;
oldSession && oldSession._signal("changeEditor", {oldEditor: this}); oldSession && oldSession._signal("changeEditor", {oldEditor: this});
session && session._signal("changeEditor", {editor: this}); session && session._signal("changeEditor", {editor: this});
}; };
@ -683,20 +692,15 @@ var Editor = function(renderer, session) {
* *
* *
**/ **/
this.onDocumentChange = function(e) { this.onDocumentChange = function(delta) {
var delta = e.data; // Rerender and emit "change" event.
var range = delta.range; var wrap = this.session.$useWrapMode;
var lastRow; var lastRow = (delta.start.row == delta.end.row ? delta.end.row : Infinity);
this.renderer.updateLines(delta.start.row, lastRow, wrap);
if (range.start.row == range.end.row && delta.action != "insertLines" && delta.action != "removeLines") this._signal("change", delta);
lastRow = range.end.row;
else // Update cursor because tab characters can influence the cursor position.
lastRow = Infinity;
this.renderer.updateLines(range.start.row, lastRow, this.session.$useWrapMode);
this._signal("change", e);
// update cursor because tab characters can influence the cursor position
this.$cursorChange(); this.$cursorChange();
this.$updateHighlightActiveLine(); this.$updateHighlightActiveLine();
}; };
@ -911,14 +915,16 @@ var Editor = function(renderer, session) {
* *
* *
**/ **/
this.onPaste = function(text) { this.onPaste = function(text, event) {
// todo this should change when paste becomes a command var e = {text: text, event: event};
if (this.$readOnly) this.commands.exec("paste", this, e);
return; };
var e = {text: text}; this.$handlePaste = function(e) {
if (typeof e == "string")
e = {text: e};
this._signal("paste", e); this._signal("paste", e);
text = e.text; var text = e.text;
if (!this.inMultiSelectMode || this.inVirtualSelectionMode) { if (!this.inMultiSelectMode || this.inVirtualSelectionMode) {
this.insert(text); this.insert(text);
} else { } else {
@ -936,7 +942,6 @@ var Editor = function(renderer, session) {
this.session.insert(range.start, lines[i]); this.session.insert(range.start, lines[i]);
} }
} }
this.renderer.scrollCursorIntoView();
}; };
this.execCommand = function(command, args) { this.execCommand = function(command, args) {
@ -1624,15 +1629,7 @@ var Editor = function(renderer, session) {
**/ **/
this.removeLines = function() { this.removeLines = function() {
var rows = this.$getSelectedRows(); var rows = this.$getSelectedRows();
var range; this.session.removeFullLines(rows.first, rows.last);
if (rows.first === 0 || rows.last+1 < this.session.getLength())
range = new Range(rows.first, 0, rows.last+1, 0);
else
range = new Range(
rows.first-1, this.session.getLine(rows.first-1).length,
rows.last, this.session.getLine(rows.last).length
);
this.session.remove(range);
this.clearSelection(); this.clearSelection();
}; };
@ -2685,6 +2682,7 @@ config.defineOptions(Editor.prototype, "editor", {
useSoftTabs: "session", useSoftTabs: "session",
tabSize: "session", tabSize: "session",
wrap: "session", wrap: "session",
indentedSoftWrap: "session",
foldStyle: "session", foldStyle: "session",
mode: "session" mode: "session"
}); });

View file

@ -578,15 +578,14 @@ var onSelectionChange = function(evt) {
* and deleting text. * and deleting text.
* @param {!Event} evt The event. * @param {!Event} evt The event.
*/ */
var onChange = function(evt) { var onChange = function(delta) {
var data = evt.data;
switch (data.action) { switch (data.action) {
case 'removeText': case 'remove':
cvox.Api.speak(data.text, 0, DELETED_PROP); cvox.Api.speak(data.text, 0, DELETED_PROP);
/* Let the future cursor change event know it's from text change. */ /* Let the future cursor change event know it's from text change. */
changed = true; changed = true;
break; break;
case 'insertText': case 'insert':
cvox.Api.speak(data.text, 0); cvox.Api.speak(data.text, 0);
/* Let the future cursor change event know it's from text change. */ /* Let the future cursor change event know it's from text change. */
changed = true; changed = true;

View file

@ -44,13 +44,12 @@ var ElasticTabstopsLite = function(editor) {
this.onExec = function() { this.onExec = function() {
recordChanges = true; recordChanges = true;
}; };
this.onChange = function(e) { this.onChange = function(delta) {
var range = e.data.range
if (recordChanges) { if (recordChanges) {
if (changedRows.indexOf(range.start.row) == -1) if (changedRows.indexOf(delta.start.row) == -1)
changedRows.push(range.start.row); changedRows.push(delta.start.row);
if (range.end.row != range.start.row) if (delta.end.row != delta.start.row)
changedRows.push(range.end.row); changedRows.push(delta.end.row);
} }
}; };
}; };

View file

@ -393,7 +393,7 @@ exports.updateCommands = function(editor, enabled) {
}; };
exports.isSupportedMode = function(modeId) { exports.isSupportedMode = function(modeId) {
return modeId && /css|less|scss|sass|stylus|html|php|twig|ejs/.test(modeId); return modeId && /css|less|scss|sass|stylus|html|php|twig|ejs|handlebars/.test(modeId);
}; };
var onChangeMode = function(e, target) { var onChangeMode = function(e, target) {

View file

@ -155,7 +155,6 @@ function getCompletionPrefix(editor) {
var doLiveAutocomplete = function(e) { var doLiveAutocomplete = function(e) {
var editor = e.editor; var editor = e.editor;
var text = e.args || "";
var hasCompleter = editor.completer && editor.completer.activated; var hasCompleter = editor.completer && editor.completer.activated;
// We don't want to autocomplete with no prefix // We don't want to autocomplete with no prefix

View file

@ -93,7 +93,7 @@ module.exports.generateSettingsMenu = function generateSettingsMenu (editor) {
}); });
var el = topmenu.appendChild(document.createElement('div')); var el = topmenu.appendChild(document.createElement('div'));
var version = "1.1.8"; var version = "1.1.9";
el.style.padding = "1em"; el.style.padding = "1em";
el.textContent = "Ace version " + version; el.textContent = "Ace version " + version;

View file

@ -47,7 +47,7 @@ var supportedModes = {
ActionScript:["as"], ActionScript:["as"],
ADA: ["ada|adb"], ADA: ["ada|adb"],
Apache_Conf: ["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"], Apache_Conf: ["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"],
AsciiDoc: ["asciidoc"], AsciiDoc: ["asciidoc|adoc"],
Assembly_x86:["asm"], Assembly_x86:["asm"],
AutoHotKey: ["ahk"], AutoHotKey: ["ahk"],
BatchFile: ["bat|cmd"], BatchFile: ["bat|cmd"],
@ -117,12 +117,13 @@ var supportedModes = {
MUSHCode: ["mc|mush"], MUSHCode: ["mc|mush"],
MySQL: ["mysql"], MySQL: ["mysql"],
Nix: ["nix"], Nix: ["nix"],
Nim: ["nim"],
ObjectiveC: ["m|mm"], ObjectiveC: ["m|mm"],
OCaml: ["ml|mli"], OCaml: ["ml|mli"],
Pascal: ["pas|p"], Pascal: ["pas|p"],
Perl: ["pl|pm"], Perl: ["pl|pm"],
pgSQL: ["pgsql"], pgSQL: ["pgsql"],
PHP: ["php|phtml"], PHP: ["php|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp"],
Powershell: ["ps1"], Powershell: ["ps1"],
Praat: ["praat|praatscript|psc|proc"], Praat: ["praat|praatscript|psc|proc"],
Prolog: ["plg|prolog"], Prolog: ["plg|prolog"],
@ -146,6 +147,7 @@ var supportedModes = {
Soy_Template:["soy"], Soy_Template:["soy"],
Space: ["space"], Space: ["space"],
SQL: ["sql"], SQL: ["sql"],
SQLServer: ["sqlserver"],
Stylus: ["styl|stylus"], Stylus: ["styl|stylus"],
SVG: ["svg"], SVG: ["svg"],
Tcl: ["tcl"], Tcl: ["tcl"],

View file

@ -1,24 +1,31 @@
.ace_static_highlight { .ace_static_highlight {
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'Droid Sans Mono', monospace; font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'Droid Sans Mono', monospace;
font-size: 12px; font-size: 12px;
white-space: pre-wrap
} }
.ace_static_highlight .ace_gutter { .ace_static_highlight .ace_gutter {
width: 25px !important; width: 2em;
float: left;
text-align: right; text-align: right;
padding: 0 3px 0 0; padding: 0 3px 0 0;
margin-right: 3px; margin-right: 3px;
position: static !important;
} }
.ace_static_highlight .ace_line { clear: both; } .ace_static_highlight.ace_show_gutter .ace_line {
padding-left: 2.6em;
}
.ace_static_highlight .ace_line { position: relative; }
.ace_static_highlight .ace_gutter-cell { .ace_static_highlight .ace_gutter-cell {
-moz-user-select: -moz-none; -moz-user-select: -moz-none;
-khtml-user-select: none; -khtml-user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
user-select: none; user-select: none;
top: 0;
bottom: 0;
left: 0;
position: absolute;
} }

View file

@ -37,6 +37,10 @@ var baseStyles = require("../requirejs/text!./static.css");
var config = require("../config"); var config = require("../config");
var dom = require("../lib/dom"); var dom = require("../lib/dom");
var SimpleTextLayer = function() {
this.config = {};
};
SimpleTextLayer.prototype = TextLayer.prototype;
var highlight = function(el, opts, callback) { var highlight = function(el, opts, callback) {
var m = el.className.match(/lang-(\w+)/); var m = el.className.match(/lang-(\w+)/);
@ -149,12 +153,8 @@ highlight.renderSync = function(input, mode, theme, lineStart, disableGutter) {
session.setUseWorker(false); session.setUseWorker(false);
session.setMode(mode); session.setMode(mode);
var textLayer = new TextLayer(document.createElement("div")); var textLayer = new SimpleTextLayer();
textLayer.setSession(session); textLayer.setSession(session);
textLayer.config = {
characterWidth: 10,
lineHeight: 20
};
session.setValue(input); session.setValue(input);
@ -171,7 +171,8 @@ highlight.renderSync = function(input, mode, theme, lineStart, disableGutter) {
// let's prepare the whole html // let's prepare the whole html
var html = "<div class='" + theme.cssClass + "'>" + var html = "<div class='" + theme.cssClass + "'>" +
"<div class='ace_static_highlight' style='counter-reset:ace_line " + (lineStart - 1) + "'>" + "<div class='ace_static_highlight" + (disableGutter ? "" : " ace_show_gutter") +
"' style='counter-reset:ace_line " + (lineStart - 1) + "'>" +
stringBuilder.join("") + stringBuilder.join("") +
"</div>" + "</div>" +
"</div>"; "</div>";

View file

@ -28,12 +28,12 @@ module.exports = {
var mode = new JavaScriptMode(); var mode = new JavaScriptMode();
var result = highlighter.render(snippet, mode, theme); var result = highlighter.render(snippet, mode, theme);
assert.equal(result.html, "<div class='ace-tomorrow'><div class='ace_static_highlight' style='counter-reset:ace_line 0'>" assert.equal(result.html, "<div class='ace-tomorrow'><div class='ace_static_highlight ace_show_gutter' style='counter-reset:ace_line 0'>"
+ "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_comment ace_doc'>/**\xa0this\xa0is\xa0a\xa0function</span>\n</div>" + "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_comment ace_doc'>/** this is a function</span>\n</div>"
+ "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_comment ace_doc'>*</span>\n</div>" + "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_comment ace_doc'>*</span>\n</div>"
+ "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_comment ace_doc'>*/</span>\n</div>" + "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_comment ace_doc'>*/</span>\n</div>"
+ "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_storage ace_type'>function</span>\xa0<span class='ace_entity ace_name ace_function'>hello</span>\xa0<span class='ace_paren ace_lparen'>(</span><span class='ace_variable ace_parameter'>a</span><span class='ace_punctuation ace_operator'>,\xa0</span><span class='ace_variable ace_parameter'>b</span><span class='ace_punctuation ace_operator'>,\xa0</span><span class='ace_variable ace_parameter'>c</span><span class='ace_paren ace_rparen'>)</span>\xa0<span class='ace_paren ace_lparen'>{</span>\n</div>" + "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_storage ace_type'>function</span> <span class='ace_entity ace_name ace_function'>hello</span> <span class='ace_paren ace_lparen'>(</span><span class='ace_variable ace_parameter'>a</span><span class='ace_punctuation ace_operator'>, </span><span class='ace_variable ace_parameter'>b</span><span class='ace_punctuation ace_operator'>, </span><span class='ace_variable ace_parameter'>c</span><span class='ace_paren ace_rparen'>)</span> <span class='ace_paren ace_lparen'>{</span>\n</div>"
+ "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span>\xa0\xa0\xa0\xa0<span class='ace_storage ace_type'>console</span><span class='ace_punctuation ace_operator'>.</span><span class='ace_support ace_function ace_firebug'>log</span><span class='ace_paren ace_lparen'>(</span><span class='ace_identifier'>a</span>\xa0<span class='ace_keyword ace_operator'>*</span>\xa0<span class='ace_identifier'>b</span>\xa0<span class='ace_keyword ace_operator'>+</span>\xa0<span class='ace_identifier'>c</span>\xa0<span class='ace_keyword ace_operator'>+</span>\xa0<span class='ace_string'>'sup$'</span><span class='ace_paren ace_rparen'>)</span><span class='ace_punctuation ace_operator'>;</span>\n</div>" + "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span> <span class='ace_storage ace_type'>console</span><span class='ace_punctuation ace_operator'>.</span><span class='ace_support ace_function ace_firebug'>log</span><span class='ace_paren ace_lparen'>(</span><span class='ace_identifier'>a</span> <span class='ace_keyword ace_operator'>*</span> <span class='ace_identifier'>b</span> <span class='ace_keyword ace_operator'>+</span> <span class='ace_identifier'>c</span> <span class='ace_keyword ace_operator'>+</span> <span class='ace_string'>'sup$'</span><span class='ace_paren ace_rparen'>)</span><span class='ace_punctuation ace_operator'>;</span>\n</div>"
+ "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_paren ace_rparen'>}</span>\n</div>" + "<div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'></span><span class='ace_paren ace_rparen'>}</span>\n</div>"
+ "</div></div>"); + "</div></div>");
assert.ok(!!result.css); assert.ok(!!result.css);

View file

@ -51,12 +51,14 @@ var themeData = [
["Dreamweaver" ], ["Dreamweaver" ],
["Eclipse" ], ["Eclipse" ],
["GitHub" ], ["GitHub" ],
["IPlastic" ],
["Solarized Light"], ["Solarized Light"],
["TextMate" ], ["TextMate" ],
["Tomorrow" ], ["Tomorrow" ],
["XCode" ], ["XCode" ],
["Kuroir"], ["Kuroir"],
["KatzenMilch"], ["KatzenMilch"],
["SQL Server" ,"sqlserver" , "light"],
["Ambiance" ,"ambiance" , "dark"], ["Ambiance" ,"ambiance" , "dark"],
["Chaos" ,"chaos" , "dark"], ["Chaos" ,"chaos" , "dark"],
["Clouds Midnight" ,"clouds_midnight" , "dark"], ["Clouds Midnight" ,"clouds_midnight" , "dark"],
@ -71,6 +73,7 @@ var themeData = [
["Solarized Dark" ,"solarized_dark" , "dark"], ["Solarized Dark" ,"solarized_dark" , "dark"],
["Terminal" ,"terminal" , "dark"], ["Terminal" ,"terminal" , "dark"],
["Tomorrow Night" ,"tomorrow_night" , "dark"], ["Tomorrow Night" ,"tomorrow_night" , "dark"],
["The Night After Tomorrow" ,"the_night_after_tomorrow" , "dark"],
["Tomorrow Night Blue" ,"tomorrow_night_blue" , "dark"], ["Tomorrow Night Blue" ,"tomorrow_night_blue" , "dark"],
["Tomorrow Night Bright","tomorrow_night_bright" , "dark"], ["Tomorrow Night Bright","tomorrow_night_bright" , "dark"],
["Tomorrow Night 80s" ,"tomorrow_night_eighties" , "dark"], ["Tomorrow Night 80s" ,"tomorrow_night_eighties" , "dark"],

View file

@ -105,7 +105,7 @@ function objectToRegExp(obj) {
this.$mousedownHandler = ed.addEventListener('mousedown', this.onMouseDown.bind(this)); this.$mousedownHandler = ed.addEventListener('mousedown', this.onMouseDown.bind(this));
this.selectionFix(ed); this.selectionFix(ed);
this.statusMessage(true); this.statusMessage(true);
} };
this.deactivate = function(reset) { this.deactivate = function(reset) {
this.cancelSearch(reset); this.cancelSearch(reset);
@ -117,7 +117,7 @@ function objectToRegExp(obj) {
} }
ed.onPaste = this.$originalEditorOnPaste; ed.onPaste = this.$originalEditorOnPaste;
this.message(''); this.message('');
} };
this.selectionFix = function(editor) { this.selectionFix = function(editor) {
// Fix selection bug: When clicked inside the editor // Fix selection bug: When clicked inside the editor
@ -128,7 +128,7 @@ function objectToRegExp(obj) {
if (editor.selection.isEmpty() && !editor.session.$emacsMark) { if (editor.selection.isEmpty() && !editor.session.$emacsMark) {
editor.clearSelection(); editor.clearSelection();
} }
} };
this.highlight = function(regexp) { this.highlight = function(regexp) {
var sess = this.$editor.session, var sess = this.$editor.session,
@ -136,7 +136,7 @@ function objectToRegExp(obj) {
new SearchHighlight(null, "ace_isearch-result", "text")); new SearchHighlight(null, "ace_isearch-result", "text"));
hl.setRegexp(regexp); hl.setRegexp(regexp);
sess._emit("changeBackMarker"); // force highlight layer redraw sess._emit("changeBackMarker"); // force highlight layer redraw
} };
this.cancelSearch = function(reset) { this.cancelSearch = function(reset) {
var e = this.$editor; var e = this.$editor;
@ -150,7 +150,7 @@ function objectToRegExp(obj) {
} }
this.highlight(null); this.highlight(null);
return Range.fromPoints(this.$currentPos, this.$currentPos); return Range.fromPoints(this.$currentPos, this.$currentPos);
} };
this.highlightAndFindWithNeedle = function(moveToNext, needleUpdateFunc) { this.highlightAndFindWithNeedle = function(moveToNext, needleUpdateFunc) {
if (!this.$editor) return null; if (!this.$editor) return null;
@ -163,7 +163,7 @@ function objectToRegExp(obj) {
if (options.needle.length === 0) { if (options.needle.length === 0) {
this.statusMessage(true); this.statusMessage(true);
return this.cancelSearch(true); return this.cancelSearch(true);
}; }
// try to find the next occurence and enable highlighting marker // try to find the next occurence and enable highlighting marker
options.start = this.$currentPos; options.start = this.$currentPos;
@ -176,13 +176,13 @@ function objectToRegExp(obj) {
this.$editor.selection.setRange(Range.fromPoints(shouldSelect ? this.$startPos : found.end, found.end)); this.$editor.selection.setRange(Range.fromPoints(shouldSelect ? this.$startPos : found.end, found.end));
if (moveToNext) this.$currentPos = found.end; if (moveToNext) this.$currentPos = found.end;
// highlight after cursor move, so selection works properly // highlight after cursor move, so selection works properly
this.highlight(options.re) this.highlight(options.re);
} }
this.statusMessage(found); this.statusMessage(found);
return found; return found;
} };
this.addString = function(s) { this.addString = function(s) {
return this.highlightAndFindWithNeedle(false, function(needle) { return this.highlightAndFindWithNeedle(false, function(needle) {
@ -192,7 +192,7 @@ function objectToRegExp(obj) {
reObj.expression += s; reObj.expression += s;
return objectToRegExp(reObj); return objectToRegExp(reObj);
}); });
} };
this.removeChar = function(c) { this.removeChar = function(c) {
return this.highlightAndFindWithNeedle(false, function(needle) { return this.highlightAndFindWithNeedle(false, function(needle) {
@ -202,7 +202,7 @@ function objectToRegExp(obj) {
reObj.expression = reObj.expression.substring(0, reObj.expression.length-1); reObj.expression = reObj.expression.substring(0, reObj.expression.length-1);
return objectToRegExp(reObj); return objectToRegExp(reObj);
}); });
} };
this.next = function(options) { this.next = function(options) {
// try to find the next occurence of whatever we have searched for // try to find the next occurence of whatever we have searched for
@ -215,29 +215,29 @@ function objectToRegExp(obj) {
return options.useCurrentOrPrevSearch && needle.length === 0 ? return options.useCurrentOrPrevSearch && needle.length === 0 ?
this.$prevNeedle || '' : needle; this.$prevNeedle || '' : needle;
}); });
} };
this.onMouseDown = function(evt) { this.onMouseDown = function(evt) {
// when mouse interaction happens then we quit incremental search // when mouse interaction happens then we quit incremental search
this.deactivate(); this.deactivate();
return true; return true;
} };
this.onPaste = function(text) { this.onPaste = function(text) {
this.addString(text); this.addString(text);
} };
this.convertNeedleToRegExp = function() { this.convertNeedleToRegExp = function() {
return this.highlightAndFindWithNeedle(false, function(needle) { return this.highlightAndFindWithNeedle(false, function(needle) {
return isRegExp(needle) ? needle : stringToRegExp(needle, 'ig'); return isRegExp(needle) ? needle : stringToRegExp(needle, 'ig');
}); });
} };
this.convertNeedleToString = function() { this.convertNeedleToString = function() {
return this.highlightAndFindWithNeedle(false, function(needle) { return this.highlightAndFindWithNeedle(false, function(needle) {
return isRegExp(needle) ? regExpToObject(needle).expression : needle; return isRegExp(needle) ? regExpToObject(needle).expression : needle;
}); });
} };
this.statusMessage = function(found) { this.statusMessage = function(found) {
var options = this.$options, msg = ''; var options = this.$options, msg = '';
@ -245,7 +245,7 @@ function objectToRegExp(obj) {
msg += 'isearch: ' + options.needle; msg += 'isearch: ' + options.needle;
msg += found ? '' : ' (not found)'; msg += found ? '' : ' (not found)';
this.message(msg); this.message(msg);
} };
this.message = function(msg) { this.message = function(msg) {
if (this.$editor.showCommandLine) { if (this.$editor.showCommandLine) {
@ -254,7 +254,7 @@ function objectToRegExp(obj) {
} else { } else {
console.log(msg); console.log(msg);
} }
} };
}).call(IncrementalSearch.prototype); }).call(IncrementalSearch.prototype);

View file

@ -428,7 +428,7 @@ exports.emacsKeys = {
"M-;": "togglecomment", "M-;": "togglecomment",
"C-/|C-x u|S-C--|C-z": "undo", "C-/|C-x u|S-C--|C-z": "undo",
"S-C-/|S-C-x u|C--|S-C-z": "redo", //infinite undo? "S-C-/|S-C-x u|C--|S-C-z": "redo", // infinite undo?
// vertical editing // vertical editing
"C-x r": "selectRectangularRegion", "C-x r": "selectRectangularRegion",
"M-x": {command: "focusCommandLine", args: "M-x "} "M-x": {command: "focusCommandLine", args: "M-x "}
@ -483,7 +483,7 @@ exports.handler.addCommands({
// different. Deactivate the mark when setMark is run with active // different. Deactivate the mark when setMark is run with active
// mark // mark
if (transientMarkModeActive && (mark || !hasNoSelection)) { if (transientMarkModeActive && (mark || !hasNoSelection)) {
if (editor.inMultiSelectMode) editor.forEachSelection({exec: editor.clearSelection.bind(editor)}) if (editor.inMultiSelectMode) editor.forEachSelection({exec: editor.clearSelection.bind(editor)});
else editor.clearSelection(); else editor.clearSelection();
if (mark) editor.pushEmacsMark(null); if (mark) editor.pushEmacsMark(null);
return; return;

View file

@ -87,9 +87,12 @@ MultiHashHandler.prototype = HashHandler.prototype;
} }
}; };
this.bindKey = function(key, command, asDefault) { this.bindKey = function(key, command, position) {
if (typeof key == "object") if (typeof key == "object") {
if (position == undefined)
position = key.position;
key = key[this.platform]; key = key[this.platform];
}
if (!key) if (!key)
return; return;
if (typeof command == "function") if (typeof command == "function")
@ -110,11 +113,15 @@ MultiHashHandler.prototype = HashHandler.prototype;
} }
var binding = this.parseKeys(keyPart); var binding = this.parseKeys(keyPart);
var id = KEY_MODS[binding.hashId] + binding.key; var id = KEY_MODS[binding.hashId] + binding.key;
this._addCommandToBinding(chain + id, command, asDefault); this._addCommandToBinding(chain + id, command, position);
}, this); }, this);
}; };
this._addCommandToBinding = function(keyId, command, asDefault) { function getPosition(command) {
return typeof command == "object" && command.bindKey
&& command.bindKey.position || 0;
}
this._addCommandToBinding = function(keyId, command, position) {
var ckb = this.commandKeyBinding, i; var ckb = this.commandKeyBinding, i;
if (!command) { if (!command) {
delete ckb[keyId]; delete ckb[keyId];
@ -126,11 +133,21 @@ MultiHashHandler.prototype = HashHandler.prototype;
} else if ((i = ckb[keyId].indexOf(command)) != -1) { } else if ((i = ckb[keyId].indexOf(command)) != -1) {
ckb[keyId].splice(i, 1); ckb[keyId].splice(i, 1);
} }
if (asDefault || command.isDefault) if (typeof position != "number") {
ckb[keyId].unshift(command); if (position || command.isDefault)
else position = -100;
ckb[keyId].push(command); else
position = getPosition(command);
}
var commands = ckb[keyId];
for (i = 0; i < commands.length; i++) {
var other = commands[i];
var otherPos = getPosition(other);
if (otherPos > position)
break;
}
commands.splice(i, 0, command);
} }
}; };
@ -219,10 +236,18 @@ MultiHashHandler.prototype = HashHandler.prototype;
} }
} }
if (data.$keyChain && keyCode > 0) if (data.$keyChain) {
data.$keyChain = ""; if ((!hashId || hashId == 4) && keyString.length == 1)
data.$keyChain = data.$keyChain.slice(0, -key.length - 1); // wait for input
else if (hashId == -1 || keyCode > 0)
data.$keyChain = ""; // reset keyChain
}
return {command: command}; return {command: command};
}; };
this.getStatusText = function(editor, data) {
return data.$keyChain || "";
};
}).call(HashHandler.prototype); }).call(HashHandler.prototype);

View file

@ -76,6 +76,7 @@ var TextInput = function(parentNode, host) {
resetSelection(); resetSelection();
}); });
this.focus = function() { this.focus = function() {
if (tempStyle) return text.focus();
text.style.position = "fixed"; text.style.position = "fixed";
text.style.top = "-1000px"; text.style.top = "-1000px";
text.focus(); text.focus();
@ -305,7 +306,7 @@ var TextInput = function(parentNode, host) {
var data = handleClipboardData(e); var data = handleClipboardData(e);
if (typeof data == "string") { if (typeof data == "string") {
if (data) if (data)
host.onPaste(data); host.onPaste(data, e);
if (useragent.isIE) if (useragent.isIE)
setTimeout(resetSelection); setTimeout(resetSelection);
event.preventDefault(e); event.preventDefault(e);

View file

@ -178,13 +178,6 @@ define(function(require, exports, module) {
return this.ace.inVirtualSelectionMode && this.ace.selection.index; return this.ace.inVirtualSelectionMode && this.ace.selection.index;
}; };
this.onChange = function(delta) { this.onChange = function(delta) {
var oldDelta = delta.data;
delta = {
start: oldDelta.range.start,
end: oldDelta.range.end,
action: oldDelta.action,
lines: oldDelta.lines || [oldDelta.text]
};// v1.2 api compatibility
if (delta.action[0] == 'i') { if (delta.action[0] == 'i') {
var change = { text: delta.lines }; var change = { text: delta.lines };
var curOp = this.curOp = this.curOp || {}; var curOp = this.curOp = this.curOp || {};
@ -264,6 +257,7 @@ define(function(require, exports, module) {
} }
if (!this.ace.inVirtualSelectionMode) if (!this.ace.inVirtualSelectionMode)
this.ace.exitMultiSelectMode(); this.ace.exitMultiSelectMode();
this.ace.session.unfold({row: line, column: ch});
this.ace.selection.moveTo(line, ch); this.ace.selection.moveTo(line, ch);
}; };
this.getCursor = function(p) { this.getCursor = function(p) {
@ -489,8 +483,12 @@ define(function(require, exports, module) {
}; };
this.scrollInfo = function() { return 0; }; this.scrollInfo = function() { return 0; };
this.scrollIntoView = function(pos, margin) { this.scrollIntoView = function(pos, margin) {
if (pos) if (pos) {
this.ace.renderer.scrollCursorIntoView(toAcePos(pos), null, margin); var renderer = this.ace.renderer;
var viewMargin = { "top": 0, "bottom": margin };
renderer.scrollCursorIntoView(toAcePos(pos),
(renderer.lineHeight * 2) / renderer.$size.scrollerHeight, viewMargin);
}
}; };
this.getLine = function(row) { return this.ace.session.getLine(row) }; this.getLine = function(row) { return this.ace.session.getLine(row) };
this.getRange = function(s, e) { this.getRange = function(s, e) {
@ -573,7 +571,6 @@ define(function(require, exports, module) {
highlight.session = null; highlight.session = null;
}; };
highlight.updateOnChange = function(delta) { highlight.updateOnChange = function(delta) {
delta = delta.data.range;// v1.2 api compatibility
var row = delta.start.row; var row = delta.start.row;
if (row == delta.end.row) highlight.cache[row] = undefined; if (row == delta.end.row) highlight.cache[row] = undefined;
else highlight.cache.splice(row, highlight.cache.length); else highlight.cache.splice(row, highlight.cache.length);
@ -650,6 +647,9 @@ define(function(require, exports, module) {
this.refresh = function() { this.refresh = function() {
return this.ace.resize(true); return this.ace.resize(true);
}; };
this.getMode = function() {
return { name : this.getOption("mode") };
}
}).call(CodeMirror.prototype); }).call(CodeMirror.prototype);
function toAcePos(cmPos) { function toAcePos(cmPos) {
return {row: cmPos.line, column: cmPos.ch}; return {row: cmPos.line, column: cmPos.ch};
@ -730,10 +730,14 @@ CodeMirror.defineExtension = function(name, fn) {
CodeMirror.prototype[name] = fn; CodeMirror.prototype[name] = fn;
}; };
dom.importCssString(".normal-mode .ace_cursor{\ dom.importCssString(".normal-mode .ace_cursor{\
border: 0!important;\ border: 1px solid red;\
background-color: red;\ background-color: red;\
opacity: 0.5;\ opacity: 0.5;\
}.ace_dialog {\ }\
.normal-mode .ace_hidden-cursors .ace_cursor{\
background-color: transparent;\
}\
.ace_dialog {\
position: absolute;\ position: absolute;\
left: 0; right: 0;\ left: 0; right: 0;\
background: white;\ background: white;\
@ -759,23 +763,6 @@ dom.importCssString(".normal-mode .ace_cursor{\
font-family: monospace;\ font-family: monospace;\
}", "vimMode"); }", "vimMode");
(function() { (function() {
function dialogDiv(cm, template, bottom) {
var wrap = cm.ace.container;
var dialog;
dialog = wrap.appendChild(document.createElement("div"));
if (bottom)
dialog.className = "ace_dialog ace_dialog-bottom";
else
dialog.className = "ace_dialog ace_dialog-top";
if (typeof template == "string") {
dialog.innerHTML = template;
} else { // Assuming it's a detached DOM element.
dialog.appendChild(template);
}
return dialog;
}
function closeNotification(cm, newVal) { function closeNotification(cm, newVal) {
if (cm.state.currentNotificationClose) if (cm.state.currentNotificationClose)
cm.state.currentNotificationClose(); cm.state.currentNotificationClose();
@ -807,7 +794,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
if (inp) { if (inp) {
if (options.value) { if (options.value) {
inp.value = options.value; inp.value = options.value;
inp.select(); if (options.select !== false) inp.select();
} }
if (options.onInput) if (options.onInput)
@ -1135,9 +1122,11 @@ dom.importCssString(".normal-mode .ace_cursor{\
} }
var numberRegex = /[\d]/; var numberRegex = /[\d]/;
var wordRegexp = [{test: CodeMirror.isWordChar}, {test: function(ch) { var wordCharTest = [CodeMirror.isWordChar, function(ch) {
return !CodeMirror.isWordChar(ch) && !/\s/.test(ch); return ch && !CodeMirror.isWordChar(ch) && !/\s/.test(ch);
}}], bigWordRegexp = [(/\S/)]; }], bigWordCharTest = [function(ch) {
return /\S/.test(ch);
}];
function makeKeyRange(start, size) { function makeKeyRange(start, size) {
var keys = []; var keys = [];
for (var i = start; i < start + size; i++) { for (var i = start; i < start + size; i++) {
@ -1179,18 +1168,30 @@ dom.importCssString(".normal-mode .ace_cursor{\
} }
var options = {}; var options = {};
function defineOption(name, defaultValue, type) { function defineOption(name, defaultValue, type, aliases, callback) {
if (defaultValue === undefined) { throw Error('defaultValue is required'); } if (defaultValue === undefined && !callback) {
throw Error('defaultValue is required unless callback is provided');
}
if (!type) { type = 'string'; } if (!type) { type = 'string'; }
options[name] = { options[name] = {
type: type, type: type,
defaultValue: defaultValue defaultValue: defaultValue,
callback: callback
}; };
setOption(name, defaultValue); if (aliases) {
for (var i = 0; i < aliases.length; i++) {
options[aliases[i]] = options[name];
}
}
if (defaultValue) {
setOption(name, defaultValue);
}
} }
function setOption(name, value, cm) { function setOption(name, value, cm, cfg) {
var option = options[name]; var option = options[name];
cfg = cfg || {};
var scope = cfg.scope;
if (!option) { if (!option) {
throw Error('Unknown option: ' + name); throw Error('Unknown option: ' + name);
} }
@ -1202,17 +1203,60 @@ dom.importCssString(".normal-mode .ace_cursor{\
value = true; value = true;
} }
} }
option.value = option.type == 'boolean' ? !!value : value; if (option.callback) {
if (scope !== 'local') {
option.callback(value, undefined);
}
if (scope !== 'global' && cm) {
option.callback(value, cm);
}
} else {
if (scope !== 'local') {
option.value = option.type == 'boolean' ? !!value : value;
}
if (scope !== 'global' && cm) {
cm.state.vim.options[name] = {value: value};
}
}
} }
function getOption(name) { function getOption(name, cm, cfg) {
var option = options[name]; var option = options[name];
cfg = cfg || {};
var scope = cfg.scope;
if (!option) { if (!option) {
throw Error('Unknown option: ' + name); throw Error('Unknown option: ' + name);
} }
return option.value; if (option.callback) {
var local = cm && option.callback(undefined, cm);
if (scope !== 'global' && local !== undefined) {
return local;
}
if (scope !== 'local') {
return option.callback();
}
return;
} else {
var local = (scope !== 'global') && (cm && cm.state.vim.options[name]);
return (local || (scope !== 'local') && option || {}).value;
}
} }
defineOption('filetype', undefined, 'string', ['ft'], function(name, cm) {
// Option is local. Do nothing for global.
if (cm === undefined) {
return;
}
// The 'filetype' option proxies to the CodeMirror 'mode' option.
if (name === undefined) {
var mode = cm.getMode().name;
return mode == 'null' ? '' : mode;
} else {
var mode = name == '' ? 'null' : name;
cm.setOption('mode', mode);
}
});
var createCircularJumpList = function() { var createCircularJumpList = function() {
var size = 100; var size = 100;
var pointer = -1; var pointer = -1;
@ -1365,8 +1409,9 @@ dom.importCssString(".normal-mode .ace_cursor{\
visualBlock: false, visualBlock: false,
lastSelection: null, lastSelection: null,
lastPastedText: null, lastPastedText: null,
sel: { sel: {},
} // Buffer-local/window-local values of vim options.
options: {}
}; };
} }
return cm.state.vim; return cm.state.vim;
@ -1417,6 +1462,8 @@ dom.importCssString(".normal-mode .ace_cursor{\
// Testing hook. // Testing hook.
maybeInitVimState_: maybeInitVimState, maybeInitVimState_: maybeInitVimState,
suppressErrorLogging: false,
InsertModeKey: InsertModeKey, InsertModeKey: InsertModeKey,
map: function(lhs, rhs, ctx) { map: function(lhs, rhs, ctx) {
// Add user defined key bindings. // Add user defined key bindings.
@ -1426,6 +1473,8 @@ dom.importCssString(".normal-mode .ace_cursor{\
// remove user defined key bindings. // remove user defined key bindings.
exCommandDispatcher.unmap(lhs, ctx); exCommandDispatcher.unmap(lhs, ctx);
}, },
// TODO: Expose setOption and getOption as instance methods. Need to decide how to namespace
// them, or somehow make them work with the existing CodeMirror setOption/getOption API.
setOption: setOption, setOption: setOption,
getOption: getOption, getOption: getOption,
defineOption: defineOption, defineOption: defineOption,
@ -1567,7 +1616,9 @@ dom.importCssString(".normal-mode .ace_cursor{\
// clear VIM state in case it's in a bad state. // clear VIM state in case it's in a bad state.
cm.state.vim = undefined; cm.state.vim = undefined;
maybeInitVimState(cm); maybeInitVimState(cm);
console['log'](e); if (!CodeMirror.Vim.suppressErrorLogging) {
console['log'](e);
}
throw e; throw e;
} }
return true; return true;
@ -1577,7 +1628,16 @@ dom.importCssString(".normal-mode .ace_cursor{\
}, },
handleEx: function(cm, input) { handleEx: function(cm, input) {
exCommandDispatcher.processCommand(cm, input); exCommandDispatcher.processCommand(cm, input);
} },
defineMotion: defineMotion,
defineAction: defineAction,
defineOperator: defineOperator,
mapCommand: mapCommand,
_mapCommand: _mapCommand,
exitVisualMode: exitVisualMode,
exitInsertMode: exitInsertMode
}; };
// Represents the current input state. // Represents the current input state.
@ -1827,12 +1887,10 @@ dom.importCssString(".normal-mode .ace_cursor{\
break; break;
case 'search': case 'search':
this.processSearch(cm, vim, command); this.processSearch(cm, vim, command);
clearInputState(cm);
break; break;
case 'ex': case 'ex':
case 'keyToEx': case 'keyToEx':
this.processEx(cm, vim, command); this.processEx(cm, vim, command);
clearInputState(cm);
break; break;
default: default:
break; break;
@ -1925,6 +1983,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
updateSearchQuery(cm, query, ignoreCase, smartCase); updateSearchQuery(cm, query, ignoreCase, smartCase);
} catch (e) { } catch (e) {
showConfirm(cm, 'Invalid regex: ' + query); showConfirm(cm, 'Invalid regex: ' + query);
clearInputState(cm);
return; return;
} }
commandDispatcher.processMotion(cm, vim, { commandDispatcher.processMotion(cm, vim, {
@ -1967,15 +2026,21 @@ dom.importCssString(".normal-mode .ace_cursor{\
} }
function onPromptKeyDown(e, query, close) { function onPromptKeyDown(e, query, close) {
var keyName = CodeMirror.keyName(e); var keyName = CodeMirror.keyName(e);
if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') { if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[' ||
(keyName == 'Backspace' && query == '')) {
vimGlobalState.searchHistoryController.pushInput(query); vimGlobalState.searchHistoryController.pushInput(query);
vimGlobalState.searchHistoryController.reset(); vimGlobalState.searchHistoryController.reset();
updateSearchQuery(cm, originalQuery); updateSearchQuery(cm, originalQuery);
clearSearchHighlight(cm); clearSearchHighlight(cm);
cm.scrollTo(originalScrollPos.left, originalScrollPos.top); cm.scrollTo(originalScrollPos.left, originalScrollPos.top);
CodeMirror.e_stop(e); CodeMirror.e_stop(e);
clearInputState(cm);
close(); close();
cm.focus(); cm.focus();
} else if (keyName == 'Ctrl-U') {
// Ctrl-U clears input.
CodeMirror.e_stop(e);
close('');
} }
} }
switch (command.searchArgs.querySrc) { switch (command.searchArgs.querySrc) {
@ -2036,10 +2101,12 @@ dom.importCssString(".normal-mode .ace_cursor{\
} }
function onPromptKeyDown(e, input, close) { function onPromptKeyDown(e, input, close) {
var keyName = CodeMirror.keyName(e), up; var keyName = CodeMirror.keyName(e), up;
if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') { if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[' ||
(keyName == 'Backspace' && input == '')) {
vimGlobalState.exCommandHistoryController.pushInput(input); vimGlobalState.exCommandHistoryController.pushInput(input);
vimGlobalState.exCommandHistoryController.reset(); vimGlobalState.exCommandHistoryController.reset();
CodeMirror.e_stop(e); CodeMirror.e_stop(e);
clearInputState(cm);
close(); close();
cm.focus(); cm.focus();
} }
@ -2047,6 +2114,10 @@ dom.importCssString(".normal-mode .ace_cursor{\
up = keyName == 'Up' ? true : false; up = keyName == 'Up' ? true : false;
input = vimGlobalState.exCommandHistoryController.nextMatch(input, up) || ''; input = vimGlobalState.exCommandHistoryController.nextMatch(input, up) || '';
close(input); close(input);
} else if (keyName == 'Ctrl-U') {
// Ctrl-U clears input.
CodeMirror.e_stop(e);
close('');
} else { } else {
if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift') if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift')
vimGlobalState.exCommandHistoryController.reset(); vimGlobalState.exCommandHistoryController.reset();
@ -2058,7 +2129,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
} else { } else {
if (vim.visualMode) { if (vim.visualMode) {
showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>', showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>',
onKeyDown: onPromptKeyDown}); onKeyDown: onPromptKeyDown, select: false});
} else { } else {
showPrompt(cm, { onClose: onPromptClose, prefix: ':', showPrompt(cm, { onClose: onPromptClose, prefix: ':',
onKeyDown: onPromptKeyDown}); onKeyDown: onPromptKeyDown});
@ -2076,8 +2147,8 @@ dom.importCssString(".normal-mode .ace_cursor{\
var registerName = inputState.registerName; var registerName = inputState.registerName;
var sel = vim.sel; var sel = vim.sel;
// TODO: Make sure cm and vim selections are identical outside visual mode. // TODO: Make sure cm and vim selections are identical outside visual mode.
var origHead = copyCursor(vim.visualMode ? sel.head: cm.getCursor('head')); var origHead = copyCursor(vim.visualMode ? clipCursorToContent(cm, sel.head): cm.getCursor('head'));
var origAnchor = copyCursor(vim.visualMode ? sel.anchor : cm.getCursor('anchor')); var origAnchor = copyCursor(vim.visualMode ? clipCursorToContent(cm, sel.anchor) : cm.getCursor('anchor'));
var oldHead = copyCursor(origHead); var oldHead = copyCursor(origHead);
var oldAnchor = copyCursor(origAnchor); var oldAnchor = copyCursor(origAnchor);
var newHead, newAnchor; var newHead, newAnchor;
@ -2113,6 +2184,8 @@ dom.importCssString(".normal-mode .ace_cursor{\
return; return;
} }
if (motionArgs.toJumplist) { if (motionArgs.toJumplist) {
if (!operator)
cm.ace.curOp.command.scrollIntoView = "center-animate"; // ace patch
var jumpList = vimGlobalState.jumpList; var jumpList = vimGlobalState.jumpList;
// if the current motion is # or *, use cachedCursor // if the current motion is # or *, use cachedCursor
var cachedCursor = jumpList.cachedCursor; var cachedCursor = jumpList.cachedCursor;
@ -2250,7 +2323,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
var operatorMoveTo = operators[operator]( var operatorMoveTo = operators[operator](
cm, operatorArgs, cmSel.ranges, oldAnchor, newHead); cm, operatorArgs, cmSel.ranges, oldAnchor, newHead);
if (vim.visualMode) { if (vim.visualMode) {
exitVisualMode(cm); exitVisualMode(cm, operatorMoveTo != null);
} }
if (operatorMoveTo) { if (operatorMoveTo) {
cm.setCursor(operatorMoveTo); cm.setCursor(operatorMoveTo);
@ -2627,6 +2700,10 @@ dom.importCssString(".normal-mode .ace_cursor{\
} }
}; };
function defineMotion(name, fn) {
motions[name] = fn;
}
function fillArray(val, times) { function fillArray(val, times) {
var arr = []; var arr = [];
for (var i = 0; i < times; i++) { for (var i = 0; i < times; i++) {
@ -2648,10 +2725,11 @@ dom.importCssString(".normal-mode .ace_cursor{\
var anchor = ranges[0].anchor, var anchor = ranges[0].anchor,
head = ranges[0].head; head = ranges[0].head;
text = cm.getRange(anchor, head); text = cm.getRange(anchor, head);
if (!isWhiteSpaceString(text)) { var lastState = vim.lastEditInputState || {};
if (lastState.motion == "moveByWords" && !isWhiteSpaceString(text)) {
// Exclude trailing whitespace if the range is not all whitespace. // Exclude trailing whitespace if the range is not all whitespace.
var match = (/\s+$/).exec(text); var match = (/\s+$/).exec(text);
if (match) { if (match && lastState.motionArgs && lastState.motionArgs.forward) {
head = offsetCursor(head, 0, - match[0].length); head = offsetCursor(head, 0, - match[0].length);
text = text.slice(0, - match[0].length); text = text.slice(0, - match[0].length);
} }
@ -2709,7 +2787,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
vimGlobalState.registerController.pushText( vimGlobalState.registerController.pushText(
args.registerName, 'delete', text, args.registerName, 'delete', text,
args.linewise, vim.visualBlock); args.linewise, vim.visualBlock);
return finalHead; return clipCursorToContent(cm, finalHead);
}, },
indent: function(cm, args, ranges) { indent: function(cm, args, ranges) {
var vim = cm.state.vim; var vim = cm.state.vim;
@ -2777,6 +2855,10 @@ dom.importCssString(".normal-mode .ace_cursor{\
} }
}; };
function defineOperator(name, fn) {
operators[name] = fn;
}
var actions = { var actions = {
jumpListWalk: function(cm, actionArgs, vim) { jumpListWalk: function(cm, actionArgs, vim) {
if (vim.visualMode) { if (vim.visualMode) {
@ -2790,6 +2872,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
var markPos = mark ? mark.find() : undefined; var markPos = mark ? mark.find() : undefined;
markPos = markPos ? markPos : cm.getCursor(); markPos = markPos ? markPos : cm.getCursor();
cm.setCursor(markPos); cm.setCursor(markPos);
cm.ace.curOp.command.scrollIntoView = "center-animate"; // ace patch
}, },
scroll: function(cm, actionArgs, vim) { scroll: function(cm, actionArgs, vim) {
if (vim.visualMode) { if (vim.visualMode) {
@ -2993,6 +3076,11 @@ dom.importCssString(".normal-mode .ace_cursor{\
if (vim.visualMode) { if (vim.visualMode) {
curStart = cm.getCursor('anchor'); curStart = cm.getCursor('anchor');
curEnd = cm.getCursor('head'); curEnd = cm.getCursor('head');
if (cursorIsBefore(curEnd, curStart)) {
var tmp = curEnd;
curEnd = curStart;
curStart = tmp;
}
curEnd.ch = lineLength(cm, curEnd.line) - 1; curEnd.ch = lineLength(cm, curEnd.line) - 1;
} else { } else {
// Repeat is the number of lines to join. Minimum 2 lines. // Repeat is the number of lines to join. Minimum 2 lines.
@ -3011,10 +3099,10 @@ dom.importCssString(".normal-mode .ace_cursor{\
cm.replaceRange(text, curStart, tmp); cm.replaceRange(text, curStart, tmp);
} }
var curFinalPos = Pos(curStart.line, finalCh); var curFinalPos = Pos(curStart.line, finalCh);
cm.setCursor(curFinalPos);
if (vim.visualMode) { if (vim.visualMode) {
exitVisualMode(cm); exitVisualMode(cm, false);
} }
cm.setCursor(curFinalPos);
}, },
newLineAndEnterInsertMode: function(cm, actionArgs, vim) { newLineAndEnterInsertMode: function(cm, actionArgs, vim) {
vim.insertMode = true; vim.insertMode = true;
@ -3177,7 +3265,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
} }
} }
if (vim.visualMode) { if (vim.visualMode) {
exitVisualMode(cm); exitVisualMode(cm, false);
} }
cm.setCursor(curPosFinal); cm.setCursor(curPosFinal);
}, },
@ -3235,7 +3323,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
curStart = cursorIsBefore(selections[0].anchor, selections[0].head) ? curStart = cursorIsBefore(selections[0].anchor, selections[0].head) ?
selections[0].anchor : selections[0].head; selections[0].anchor : selections[0].head;
cm.setCursor(curStart); cm.setCursor(curStart);
exitVisualMode(cm); exitVisualMode(cm, false);
} else { } else {
cm.setCursor(offsetCursor(curEnd, 0, -1)); cm.setCursor(offsetCursor(curEnd, 0, -1));
} }
@ -3283,6 +3371,10 @@ dom.importCssString(".normal-mode .ace_cursor{\
exitInsertMode: exitInsertMode exitInsertMode: exitInsertMode
}; };
function defineAction(name, fn) {
actions[name] = fn;
}
/* /*
* Below are miscellaneous utility functions used by vim.js * Below are miscellaneous utility functions used by vim.js
*/ */
@ -3412,9 +3504,6 @@ dom.importCssString(".normal-mode .ace_cursor{\
function lineLength(cm, lineNum) { function lineLength(cm, lineNum) {
return cm.getLine(lineNum).length; return cm.getLine(lineNum).length;
} }
function reverse(s){
return s.split('').reverse().join('');
}
function trim(s) { function trim(s) {
if (s.trim) { if (s.trim) {
return s.trim(); return s.trim();
@ -3728,59 +3817,38 @@ dom.importCssString(".normal-mode .ace_cursor{\
// Seek to first word or non-whitespace character, depending on if // Seek to first word or non-whitespace character, depending on if
// noSymbol is true. // noSymbol is true.
var textAfterIdx = line.substring(idx); var test = noSymbol ? wordCharTest[0] : bigWordCharTest [0];
var firstMatchedChar; while (!test(line.charAt(idx))) {
if (noSymbol) { idx++;
firstMatchedChar = textAfterIdx.search(/\w/); if (idx >= line.length) { return null; }
} else {
firstMatchedChar = textAfterIdx.search(/\S/);
} }
if (firstMatchedChar == -1) {
return null;
}
idx += firstMatchedChar;
textAfterIdx = line.substring(idx);
var textBeforeIdx = line.substring(0, idx);
var matchRegex;
// Greedy matchers for the "word" we are trying to expand.
if (bigWord) { if (bigWord) {
matchRegex = /^\S+/; test = bigWordCharTest[0];
} else { } else {
if ((/\w/).test(line.charAt(idx))) { test = wordCharTest[0];
matchRegex = /^\w+/; if (!test(line.charAt(idx))) {
} else { test = wordCharTest[1];
matchRegex = /^[^\w\s]+/;
} }
} }
var wordAfterRegex = matchRegex.exec(textAfterIdx); var end = idx, start = idx;
var wordStart = idx; while (test(line.charAt(end)) && end < line.length) { end++; }
var wordEnd = idx + wordAfterRegex[0].length; while (test(line.charAt(start)) && start >= 0) { start--; }
// TODO: Find a better way to do this. It will be slow on very long lines. start++;
var revTextBeforeIdx = reverse(textBeforeIdx);
var wordBeforeRegex = matchRegex.exec(revTextBeforeIdx);
if (wordBeforeRegex) {
wordStart -= wordBeforeRegex[0].length;
}
if (inclusive) { if (inclusive) {
// If present, trim all whitespace after word. // If present, include all whitespace after word.
// Otherwise, trim all whitespace before word. // Otherwise, include all whitespace before word, except indentation.
var textAfterWordEnd = line.substring(wordEnd); var wordEnd = end;
var whitespacesAfterWord = textAfterWordEnd.match(/^\s*/)[0].length; while (/\s/.test(line.charAt(end)) && end < line.length) { end++; }
if (whitespacesAfterWord > 0) { if (wordEnd == end) {
wordEnd += whitespacesAfterWord; var wordStart = start;
} else { while (/\s/.test(line.charAt(start - 1)) && start > 0) { start--; }
var revTrim = revTextBeforeIdx.length - wordStart; if (!start) { start = wordStart; }
var textBeforeWordStart = revTextBeforeIdx.substring(revTrim);
var whitespacesBeforeWord = textBeforeWordStart.match(/^\s*/)[0].length;
wordStart -= whitespacesBeforeWord;
} }
} }
return { start: Pos(cur.line, start), end: Pos(cur.line, end) };
return { start: Pos(cur.line, wordStart),
end: Pos(cur.line, wordEnd) };
} }
function recordJumpPosition(cm, oldCur, newCur) { function recordJumpPosition(cm, oldCur, newCur) {
@ -3938,7 +4006,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
var pos = cur.ch; var pos = cur.ch;
var line = cm.getLine(lineNum); var line = cm.getLine(lineNum);
var dir = forward ? 1 : -1; var dir = forward ? 1 : -1;
var regexps = bigWord ? bigWordRegexp : wordRegexp; var charTests = bigWord ? bigWordCharTest: wordCharTest;
if (emptyLineIsWord && line == '') { if (emptyLineIsWord && line == '') {
lineNum += dir; lineNum += dir;
@ -3958,11 +4026,11 @@ dom.importCssString(".normal-mode .ace_cursor{\
// Find bounds of next word. // Find bounds of next word.
while (pos != stop) { while (pos != stop) {
var foundWord = false; var foundWord = false;
for (var i = 0; i < regexps.length && !foundWord; ++i) { for (var i = 0; i < charTests.length && !foundWord; ++i) {
if (regexps[i].test(line.charAt(pos))) { if (charTests[i](line.charAt(pos))) {
wordStart = pos; wordStart = pos;
// Advance to end of word. // Advance to end of word.
while (pos != stop && regexps[i].test(line.charAt(pos))) { while (pos != stop && charTests[i](line.charAt(pos))) {
pos += dir; pos += dir;
} }
wordEnd = pos; wordEnd = pos;
@ -4279,6 +4347,12 @@ dom.importCssString(".normal-mode .ace_cursor{\
}, },
setReversed: function(reversed) { setReversed: function(reversed) {
vimGlobalState.isReversed = reversed; vimGlobalState.isReversed = reversed;
},
getScrollbarAnnotate: function() {
return this.annotate;
},
setScrollbarAnnotate: function(annotate) {
this.annotate = annotate;
} }
}; };
function getSearchState(cm) { function getSearchState(cm) {
@ -4288,7 +4362,8 @@ dom.importCssString(".normal-mode .ace_cursor{\
function dialog(cm, template, shortText, onClose, options) { function dialog(cm, template, shortText, onClose, options) {
if (cm.openDialog) { if (cm.openDialog) {
cm.openDialog(template, onClose, { bottom: true, value: options.value, cm.openDialog(template, onClose, { bottom: true, value: options.value,
onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp }); onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp,
selectValueOnOpen: false});
} }
else { else {
onClose(prompt(shortText, '')); onClose(prompt(shortText, ''));
@ -4557,14 +4632,21 @@ dom.importCssString(".normal-mode .ace_cursor{\
}; };
} }
function highlightSearchMatches(cm, query) { function highlightSearchMatches(cm, query) {
var overlay = getSearchState(cm).getOverlay(); var searchState = getSearchState(cm);
var overlay = searchState.getOverlay();
if (!overlay || query != overlay.query) { if (!overlay || query != overlay.query) {
if (overlay) { if (overlay) {
cm.removeOverlay(overlay); cm.removeOverlay(overlay);
} }
overlay = searchOverlay(query); overlay = searchOverlay(query);
cm.addOverlay(overlay); cm.addOverlay(overlay);
getSearchState(cm).setOverlay(overlay); if (cm.showMatchesOnScrollbar) {
if (searchState.getScrollbarAnnotate()) {
searchState.getScrollbarAnnotate().clear();
}
searchState.setScrollbarAnnotate(cm.showMatchesOnScrollbar(query));
}
searchState.setOverlay(overlay);
} }
} }
function findNext(cm, prev, query, repeat) { function findNext(cm, prev, query, repeat) {
@ -4589,8 +4671,13 @@ dom.importCssString(".normal-mode .ace_cursor{\
}); });
} }
function clearSearchHighlight(cm) { function clearSearchHighlight(cm) {
var state = getSearchState(cm);
cm.removeOverlay(getSearchState(cm).getOverlay()); cm.removeOverlay(getSearchState(cm).getOverlay());
getSearchState(cm).setOverlay(null); state.setOverlay(null);
if (state.getScrollbarAnnotate()) {
state.getScrollbarAnnotate().clear();
state.setScrollbarAnnotate(null);
}
} }
/** /**
* Check if pos is in the specified range, INCLUSIVE. * Check if pos is in the specified range, INCLUSIVE.
@ -4631,6 +4718,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
// pair of commands that have a shared prefix, at least one of their // pair of commands that have a shared prefix, at least one of their
// shortNames must not match the prefix of the other command. // shortNames must not match the prefix of the other command.
var defaultExCommandMap = [ var defaultExCommandMap = [
{ name: 'colorscheme', shortName: 'colo' },
{ name: 'map' }, { name: 'map' },
{ name: 'imap', shortName: 'im' }, { name: 'imap', shortName: 'im' },
{ name: 'nmap', shortName: 'nm' }, { name: 'nmap', shortName: 'nm' },
@ -4639,7 +4727,10 @@ dom.importCssString(".normal-mode .ace_cursor{\
{ name: 'write', shortName: 'w' }, { name: 'write', shortName: 'w' },
{ name: 'undo', shortName: 'u' }, { name: 'undo', shortName: 'u' },
{ name: 'redo', shortName: 'red' }, { name: 'redo', shortName: 'red' },
{ name: 'set', shortName: 'set' }, { name: 'set', shortName: 'se' },
{ name: 'set', shortName: 'se' },
{ name: 'setlocal', shortName: 'setl' },
{ name: 'setglobal', shortName: 'setg' },
{ name: 'sort', shortName: 'sor' }, { name: 'sort', shortName: 'sor' },
{ name: 'substitute', shortName: 's', possiblyAsync: true }, { name: 'substitute', shortName: 's', possiblyAsync: true },
{ name: 'nohlsearch', shortName: 'noh' }, { name: 'nohlsearch', shortName: 'noh' },
@ -4652,6 +4743,13 @@ dom.importCssString(".normal-mode .ace_cursor{\
}; };
ExCommandDispatcher.prototype = { ExCommandDispatcher.prototype = {
processCommand: function(cm, input, opt_params) { processCommand: function(cm, input, opt_params) {
var that = this;
cm.operation(function () {
cm.curOp.isVimOp = true;
that._processCommand(cm, input, opt_params);
});
},
_processCommand: function(cm, input, opt_params) {
var vim = cm.state.vim; var vim = cm.state.vim;
var commandHistoryRegister = vimGlobalState.registerController.getRegister(':'); var commandHistoryRegister = vimGlobalState.registerController.getRegister(':');
var previousCommand = commandHistoryRegister.toString(); var previousCommand = commandHistoryRegister.toString();
@ -4864,6 +4962,13 @@ dom.importCssString(".normal-mode .ace_cursor{\
}; };
var exCommands = { var exCommands = {
colorscheme: function(cm, params) {
if (!params.args || params.args.length < 1) {
showConfirm(cm, cm.getOption('theme'));
return;
}
cm.setOption('theme', params.args[0]);
},
map: function(cm, params, ctx) { map: function(cm, params, ctx) {
var mapArgs = params.args; var mapArgs = params.args;
if (!mapArgs || mapArgs.length < 2) { if (!mapArgs || mapArgs.length < 2) {
@ -4897,6 +5002,9 @@ dom.importCssString(".normal-mode .ace_cursor{\
}, },
set: function(cm, params) { set: function(cm, params) {
var setArgs = params.args; var setArgs = params.args;
// Options passed through to the setOption/getOption calls. May be passed in by the
// local/global versions of the set command
var setCfg = params.setCfg || {};
if (!setArgs || setArgs.length < 1) { if (!setArgs || setArgs.length < 1) {
if (cm) { if (cm) {
showConfirm(cm, 'Invalid mapping: ' + params.input); showConfirm(cm, 'Invalid mapping: ' + params.input);
@ -4920,24 +5028,35 @@ dom.importCssString(".normal-mode .ace_cursor{\
optionName = optionName.substring(2); optionName = optionName.substring(2);
value = false; value = false;
} }
var optionIsBoolean = options[optionName] && options[optionName].type == 'boolean'; var optionIsBoolean = options[optionName] && options[optionName].type == 'boolean';
if (optionIsBoolean && value == undefined) { if (optionIsBoolean && value == undefined) {
// Calling set with a boolean option sets it to true. // Calling set with a boolean option sets it to true.
value = true; value = true;
} }
if (!optionIsBoolean && !value || forceGet) { // If no value is provided, then we assume this is a get.
var oldValue = getOption(optionName); if (!optionIsBoolean && value === undefined || forceGet) {
// If no value is provided, then we assume this is a get. var oldValue = getOption(optionName, cm, setCfg);
if (oldValue === true || oldValue === false) { if (oldValue === true || oldValue === false) {
showConfirm(cm, ' ' + (oldValue ? '' : 'no') + optionName); showConfirm(cm, ' ' + (oldValue ? '' : 'no') + optionName);
} else { } else {
showConfirm(cm, ' ' + optionName + '=' + oldValue); showConfirm(cm, ' ' + optionName + '=' + oldValue);
} }
} else { } else {
setOption(optionName, value, cm); setOption(optionName, value, cm, setCfg);
} }
}, },
registers: function(cm,params) { setlocal: function (cm, params) {
// setCfg is passed through to setOption
params.setCfg = {scope: 'local'};
this.set(cm, params);
},
setglobal: function (cm, params) {
// setCfg is passed through to setOption
params.setCfg = {scope: 'global'};
this.set(cm, params);
},
registers: function(cm, params) {
var regArgs = params.args; var regArgs = params.args;
var registers = vimGlobalState.registerController.registers; var registers = vimGlobalState.registerController.registers;
var regInfo = '----------Registers----------<br><br>'; var regInfo = '----------Registers----------<br><br>';
@ -5417,6 +5536,19 @@ dom.importCssString(".normal-mode .ace_cursor{\
} }
} }
function _mapCommand(command) {
defaultKeymap.push(command);
}
function mapCommand(keys, type, name, args, extra) {
var command = {keys: keys, type: type};
command[type] = name;
command[type + "Args"] = args;
for (var key in extra)
command[key] = extra[key];
_mapCommand(command);
}
// The timeout in milliseconds for the two-character ESC keymap should be // The timeout in milliseconds for the two-character ESC keymap should be
// adjusted according to your typing speed to prevent false positives. // adjusted according to your typing speed to prevent false positives.
defineOption('insertModeEscKeysTimeout', 200, 'number'); defineOption('insertModeEscKeysTimeout', 200, 'number');
@ -5546,7 +5678,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
} }
function updateFakeCursor(cm) { function updateFakeCursor(cm) {
var vim = cm.state.vim; var vim = cm.state.vim;
var from = copyCursor(vim.sel.head); var from = clipCursorToContent(cm, copyCursor(vim.sel.head));
var to = offsetCursor(from, 0, 1); var to = offsetCursor(from, 0, 1);
if (vim.fakeCursor) { if (vim.fakeCursor) {
vim.fakeCursor.clear(); vim.fakeCursor.clear();
@ -5557,7 +5689,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
var anchor = cm.getCursor('anchor'); var anchor = cm.getCursor('anchor');
var head = cm.getCursor('head'); var head = cm.getCursor('head');
// Enter or exit visual mode to match mouse selection. // Enter or exit visual mode to match mouse selection.
if (vim.visualMode && cursorEqual(head, anchor) && lineLength(cm, head.line) > head.ch) { if (vim.visualMode && !cm.somethingSelected()) {
exitVisualMode(cm, false); exitVisualMode(cm, false);
} else if (!vim.visualMode && !vim.insertMode && cm.somethingSelected()) { } else if (!vim.visualMode && !vim.insertMode && cm.somethingSelected()) {
vim.visualMode = true; vim.visualMode = true;
@ -5597,6 +5729,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
var macroModeState = vimGlobalState.macroModeState; var macroModeState = vimGlobalState.macroModeState;
var lastChange = macroModeState.lastInsertModeChanges; var lastChange = macroModeState.lastInsertModeChanges;
var keyName = CodeMirror.keyName(e); var keyName = CodeMirror.keyName(e);
if (!keyName) { return; }
function onKeyFound() { function onKeyFound() {
lastChange.changes.push(new InsertModeKey(keyName)); lastChange.changes.push(new InsertModeKey(keyName));
return true; return true;
@ -5790,7 +5923,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
}, true); }, true);
} }
return isHandled; return isHandled;
}; }
exports.CodeMirror = CodeMirror; exports.CodeMirror = CodeMirror;
var getVim = Vim.maybeInitVimState_; var getVim = Vim.maybeInitVimState_;
exports.handler = { exports.handler = {
@ -5804,9 +5937,9 @@ dom.importCssString(".normal-mode .ace_cursor{\
if (!vim.insertMode) { if (!vim.insertMode) {
var isbackwards = !sel.cursor var isbackwards = !sel.cursor
? session.selection.isBackwards() || session.selection.isEmpty() ? session.selection.isBackwards() || session.selection.isEmpty()
: Range.comparePoints(sel.cursor, sel.start) <= 0 : Range.comparePoints(sel.cursor, sel.start) <= 0;
if (!isbackwards && left > w) if (!isbackwards && left > w)
left -= w left -= w;
} }
if (!vim.insertMode && vim.status) { if (!vim.insertMode && vim.status) {
h = h / 2; h = h / 2;
@ -5970,13 +6103,13 @@ dom.importCssString(".normal-mode .ace_cursor{\
}; };
var renderVirtualNumbers = { var renderVirtualNumbers = {
getText: function(session, row) { getText: function(session, row) {
return (Math.abs(session.selection.lead.row - row) || (row + 1 + (row < 9? "\xb7" : "" ))) + "" return (Math.abs(session.selection.lead.row - row) || (row + 1 + (row < 9? "\xb7" : "" ))) + "";
}, },
getWidth: function(session, lastLineNumber, config) { getWidth: function(session, lastLineNumber, config) {
return session.getLength().toString().length * config.characterWidth; return session.getLength().toString().length * config.characterWidth;
}, },
update: function(e, editor) { update: function(e, editor) {
editor.renderer.$loop.schedule(editor.renderer.CHANGE_GUTTER) editor.renderer.$loop.schedule(editor.renderer.CHANGE_GUTTER);
}, },
attach: function(editor) { attach: function(editor) {
editor.renderer.$gutterLayer.$renderer = this; editor.renderer.$gutterLayer.$renderer = this;
@ -6021,7 +6154,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
if (cm.ace.inVirtualSelectionMode) if (cm.ace.inVirtualSelectionMode)
cm.ace.on("beforeEndOperation", delayedExecAceCommand); cm.ace.on("beforeEndOperation", delayedExecAceCommand);
else else
delayedExecAceCommand(null, cm.ace) delayedExecAceCommand(null, cm.ace);
}; };
function delayedExecAceCommand(op, ace) { function delayedExecAceCommand(op, ace) {
ace.off("beforeEndOperation", delayedExecAceCommand); ace.off("beforeEndOperation", delayedExecAceCommand);
@ -6040,5 +6173,5 @@ dom.importCssString(".normal-mode .ace_cursor{\
exports.handler.actions = actions; exports.handler.actions = actions;
exports.Vim = Vim; exports.Vim = Vim;
Vim.map("Y", "yy"); Vim.map("Y", "yy", "normal");
}); });

View file

@ -34,6 +34,7 @@ editor.session.setMode(new JavaScriptMode());
function CodeMirror(place, opts) { function CodeMirror(place, opts) {
if (opts.value != null) if (opts.value != null)
editor.session.setValue(opts.value); editor.session.setValue(opts.value);
editor.setOption("indentedSoftWrap", false);
editor.setOption("wrap", opts.lineWrapping); editor.setOption("wrap", opts.lineWrapping);
editor.setOption("useSoftTabs", !opts.indentWithTabs); editor.setOption("useSoftTabs", !opts.indentWithTabs);
editor.setKeyboardHandler(null); editor.setKeyboardHandler(null);
@ -58,6 +59,7 @@ function CodeMirror(place, opts) {
cm.setSize(500, 300); cm.setSize(500, 300);
return cm; return cm;
} }
CodeMirror.defineMode = function() {}
for (var key in vim.CodeMirror) for (var key in vim.CodeMirror)
CodeMirror[key] = vim.CodeMirror[key]; CodeMirror[key] = vim.CodeMirror[key];
var editor; var editor;
@ -73,6 +75,9 @@ function test(name, fn) {
} }
vim.CodeMirror.Vim.unmap("Y"); vim.CodeMirror.Vim.unmap("Y");
vim.CodeMirror.Vim.defineEx('write', 'w', function(cm) {
CodeMirror.commands.save(cm);
});
@ -592,7 +597,7 @@ testVim('{', function(cm, vim, helpers) {
helpers.doKeys('6', '{'); helpers.doKeys('6', '{');
helpers.assertCursorAt(0, 0); helpers.assertCursorAt(0, 0);
}, { value: 'a\n\nb\nc\n\nd' }); }, { value: 'a\n\nb\nc\n\nd' });
testVim('paragraph motions', function(cm, vim, helpers) { testVim('paragraph_motions', function(cm, vim, helpers) {
cm.setCursor(10, 0); cm.setCursor(10, 0);
helpers.doKeys('{'); helpers.doKeys('{');
helpers.assertCursorAt(4, 0); helpers.assertCursorAt(4, 0);
@ -685,7 +690,7 @@ testVim('dl_eol', function(cm, vim, helpers) {
var register = helpers.getRegisterController().getRegister(); var register = helpers.getRegisterController().getRegister();
eq(' ', register.toString()); eq(' ', register.toString());
is(!register.linewise); is(!register.linewise);
helpers.assertCursorAt(0, 6); helpers.assertCursorAt(0, 5);
}, { value: ' word1 ' }); }, { value: ' word1 ' });
testVim('dl_repeat', function(cm, vim, helpers) { testVim('dl_repeat', function(cm, vim, helpers) {
var curStart = makeCursor(0, 0); var curStart = makeCursor(0, 0);
@ -767,6 +772,16 @@ testVim('dw_word', function(cm, vim, helpers) {
is(!register.linewise); is(!register.linewise);
eqPos(curStart, cm.getCursor()); eqPos(curStart, cm.getCursor());
}, { value: ' word1 word2' }); }, { value: ' word1 word2' });
testVim('dw_unicode_word', function(cm, vim, helpers) {
helpers.doKeys('d', 'w');
eq(cm.getValue().length, 10);
helpers.doKeys('d', 'w');
eq(cm.getValue().length, 6);
helpers.doKeys('d', 'w');
eq(cm.getValue().length, 5);
helpers.doKeys('d', 'e');
eq(cm.getValue().length, 2);
}, { value: ' \u0562\u0561\u0580\u0587\xbbe\xb5g ' });
testVim('dw_only_word', function(cm, vim, helpers) { testVim('dw_only_word', function(cm, vim, helpers) {
// Test that if there is only 1 word left, dw deletes till the end of the // Test that if there is only 1 word left, dw deletes till the end of the
// line. // line.
@ -776,7 +791,7 @@ testVim('dw_only_word', function(cm, vim, helpers) {
var register = helpers.getRegisterController().getRegister(); var register = helpers.getRegisterController().getRegister();
eq('word1 ', register.toString()); eq('word1 ', register.toString());
is(!register.linewise); is(!register.linewise);
helpers.assertCursorAt(0, 1); helpers.assertCursorAt(0, 0);
}, { value: ' word1 ' }); }, { value: ' word1 ' });
testVim('dw_eol', function(cm, vim, helpers) { testVim('dw_eol', function(cm, vim, helpers) {
// Assert that dw does not delete the newline if last word to delete is at end // Assert that dw does not delete the newline if last word to delete is at end
@ -787,7 +802,7 @@ testVim('dw_eol', function(cm, vim, helpers) {
var register = helpers.getRegisterController().getRegister(); var register = helpers.getRegisterController().getRegister();
eq('word1', register.toString()); eq('word1', register.toString());
is(!register.linewise); is(!register.linewise);
helpers.assertCursorAt(0, 1); helpers.assertCursorAt(0, 0);
}, { value: ' word1\nword2' }); }, { value: ' word1\nword2' });
testVim('dw_eol_with_multiple_newlines', function(cm, vim, helpers) { testVim('dw_eol_with_multiple_newlines', function(cm, vim, helpers) {
// Assert that dw does not delete the newline if last word to delete is at end // Assert that dw does not delete the newline if last word to delete is at end
@ -798,7 +813,7 @@ testVim('dw_eol_with_multiple_newlines', function(cm, vim, helpers) {
var register = helpers.getRegisterController().getRegister(); var register = helpers.getRegisterController().getRegister();
eq('word1', register.toString()); eq('word1', register.toString());
is(!register.linewise); is(!register.linewise);
helpers.assertCursorAt(0, 1); helpers.assertCursorAt(0, 0);
}, { value: ' word1\n\nword2' }); }, { value: ' word1\n\nword2' });
testVim('dw_empty_line_followed_by_whitespace', function(cm, vim, helpers) { testVim('dw_empty_line_followed_by_whitespace', function(cm, vim, helpers) {
cm.setCursor(0, 0); cm.setCursor(0, 0);
@ -844,7 +859,7 @@ testVim('dw_repeat', function(cm, vim, helpers) {
var register = helpers.getRegisterController().getRegister(); var register = helpers.getRegisterController().getRegister();
eq('word1\nword2', register.toString()); eq('word1\nword2', register.toString());
is(!register.linewise); is(!register.linewise);
helpers.assertCursorAt(0, 1); helpers.assertCursorAt(0, 0);
}, { value: ' word1\nword2' }); }, { value: ' word1\nword2' });
testVim('de_word_start_and_empty_lines', function(cm, vim, helpers) { testVim('de_word_start_and_empty_lines', function(cm, vim, helpers) {
cm.setCursor(0, 0); cm.setCursor(0, 0);
@ -1062,6 +1077,17 @@ testVim('cc_multiply_repeat', function(cm, vim, helpers) {
is(register.linewise); is(register.linewise);
eq('vim-insert', cm.getOption('keyMap')); eq('vim-insert', cm.getOption('keyMap'));
}); });
testVim('ct', function(cm, vim, helpers) {
cm.setCursor(0, 9);
helpers.doKeys('c', 't', 'w');
eq(' word1 word3', cm.getValue());
helpers.doKeys('<Esc>', 'c', '|');
eq(' word3', cm.getValue());
helpers.assertCursorAt(0, 0);
helpers.doKeys('<Esc>', '2', 'u', 'w', 'h');
helpers.doKeys('c', '2', 'g', 'e');
eq(' wordword3', cm.getValue());
}, { value: ' word1 word2 word3'});
testVim('cc_should_not_append_to_document', function(cm, vim, helpers) { testVim('cc_should_not_append_to_document', function(cm, vim, helpers) {
var expectedLineCount = cm.lineCount(); var expectedLineCount = cm.lineCount();
cm.setCursor(cm.lastLine(), 0); cm.setCursor(cm.lastLine(), 0);
@ -1371,7 +1397,7 @@ testVim('D', function(cm, vim, helpers) {
var register = helpers.getRegisterController().getRegister(); var register = helpers.getRegisterController().getRegister();
eq('rd1', register.toString()); eq('rd1', register.toString());
is(!register.linewise); is(!register.linewise);
helpers.assertCursorAt(0, 3); helpers.assertCursorAt(0, 2);
}, { value: ' word1\nword2\n word3' }); }, { value: ' word1\nword2\n word3' });
testVim('C', function(cm, vim, helpers) { testVim('C', function(cm, vim, helpers) {
var curStart = makeCursor(0, 3); var curStart = makeCursor(0, 3);
@ -1962,8 +1988,11 @@ testVim('visual_block_move_to_eol', function(cm, vim, helpers) {
cm.setCursor(0, 0); cm.setCursor(0, 0);
helpers.doKeys('<C-v>', 'G', '$'); helpers.doKeys('<C-v>', 'G', '$');
var selections = cm.getSelections().join(); var selections = cm.getSelections().join();
console.log(selections); eq('123,45,6', selections);
eq("123,45,6", selections); // Checks that with cursor at Infinity, finding words backwards still works.
helpers.doKeys('2', 'k', 'b');
selections = cm.getSelections().join();
eq('1', selections);
}, {value: '123\n45\n6'}); }, {value: '123\n45\n6'});
testVim('visual_block_different_line_lengths', function(cm, vim, helpers) { testVim('visual_block_different_line_lengths', function(cm, vim, helpers) {
// test the block selection with lines of different length // test the block selection with lines of different length
@ -2053,6 +2082,11 @@ testVim('visual_join', function(cm, vim, helpers) {
eq(' 1 2 3\n 4\n 5', cm.getValue()); eq(' 1 2 3\n 4\n 5', cm.getValue());
is(!vim.visualMode); is(!vim.visualMode);
}, { value: ' 1\n 2\n 3\n 4\n 5' }); }, { value: ' 1\n 2\n 3\n 4\n 5' });
testVim('visual_join_2', function(cm, vim, helpers) {
helpers.doKeys('G', 'V', 'g', 'g', 'J');
eq('1 2 3 4 5 6 ', cm.getValue());
is(!vim.visualMode);
}, { value: '1\n2\n3\n4\n5\n6\n'});
testVim('visual_blank', function(cm, vim, helpers) { testVim('visual_blank', function(cm, vim, helpers) {
helpers.doKeys('v', 'k'); helpers.doKeys('v', 'k');
eq(vim.visualMode, true); eq(vim.visualMode, true);
@ -2260,6 +2294,15 @@ testVim('S_visual', function(cm, vim, helpers) {
eq('\ncc', cm.getValue()); eq('\ncc', cm.getValue());
}, { value: 'aa\nbb\ncc'}); }, { value: 'aa\nbb\ncc'});
testVim('d_/', function(cm, vim, helpers) {
cm.openDialog = helpers.fakeOpenDialog('match');
helpers.doKeys('2', 'd', '/');
helpers.assertCursorAt(0, 0);
eq('match \n next', cm.getValue());
cm.openDialog = helpers.fakeOpenDialog('2');
helpers.doKeys('d', ':');
// TODO eq(' next', cm.getValue());
}, { value: 'text match match \n next' });
testVim('/ and n/N', function(cm, vim, helpers) { testVim('/ and n/N', function(cm, vim, helpers) {
cm.openDialog = helpers.fakeOpenDialog('match'); cm.openDialog = helpers.fakeOpenDialog('match');
helpers.doKeys('/'); helpers.doKeys('/');
@ -2777,6 +2820,44 @@ testVim('exCommand_history', function(cm, vim, helpers) {
onKeyDown({keyCode: keyCodes.Up}, input, close); onKeyDown({keyCode: keyCodes.Up}, input, close);
eq(input, 'sort'); eq(input, 'sort');
}, {value: ''}); }, {value: ''});
testVim('search_clear', function(cm, vim, helpers) {
var onKeyDown;
var input = '';
var keyCodes = {
Ctrl: 17,
u: 85
};
cm.openDialog = function(template, callback, options) {
onKeyDown = options.onKeyDown;
};
var close = function(newVal) {
if (typeof newVal == 'string') input = newVal;
}
helpers.doKeys('/');
input = 'foo';
onKeyDown({keyCode: keyCodes.Ctrl}, input, close);
onKeyDown({keyCode: keyCodes.u, ctrlKey: true}, input, close);
eq(input, '');
});
testVim('exCommand_clear', function(cm, vim, helpers) {
var onKeyDown;
var input = '';
var keyCodes = {
Ctrl: 17,
u: 85
};
cm.openDialog = function(template, callback, options) {
onKeyDown = options.onKeyDown;
};
var close = function(newVal) {
if (typeof newVal == 'string') input = newVal;
}
helpers.doKeys(':');
input = 'foo';
onKeyDown({keyCode: keyCodes.Ctrl}, input, close);
onKeyDown({keyCode: keyCodes.u, ctrlKey: true}, input, close);
eq(input, '');
});
testVim('.', function(cm, vim, helpers) { testVim('.', function(cm, vim, helpers) {
cm.setCursor(0, 0); cm.setCursor(0, 0);
helpers.doKeys('2', 'd', 'w'); helpers.doKeys('2', 'd', 'w');
@ -3204,7 +3285,7 @@ testVim('scrollMotion', function(cm, vim, helpers){
cm.refresh(); //ace! cm.refresh(); //ace!
prevScrollInfo = cm.getScrollInfo(); prevScrollInfo = cm.getScrollInfo();
helpers.doKeys('<C-y>'); helpers.doKeys('<C-y>');
eq(prevCursor.line - 1, cm.getCursor().line); eq(prevCursor.line - 1, cm.getCursor().line, "Y");
is(prevScrollInfo.top > cm.getScrollInfo().top); is(prevScrollInfo.top > cm.getScrollInfo().top);
}, { value: scrollMotionSandbox}); }, { value: scrollMotionSandbox});
@ -3727,17 +3808,111 @@ testVim('set_string', function(cm, vim, helpers) {
eq('c', CodeMirror.Vim.getOption('testoption')); eq('c', CodeMirror.Vim.getOption('testoption'));
}); });
testVim('ex_set_string', function(cm, vim, helpers) { testVim('ex_set_string', function(cm, vim, helpers) {
CodeMirror.Vim.defineOption('testoption', 'a', 'string'); CodeMirror.Vim.defineOption('testopt', 'a', 'string');
// Test default value is set. // Test default value is set.
eq('a', CodeMirror.Vim.getOption('testoption')); eq('a', CodeMirror.Vim.getOption('testopt'));
try { try {
// Test fail to set 'notestoption' // Test fail to set 'notestopt'
helpers.doEx('set notestoption=b'); helpers.doEx('set notestopt=b');
fail(); fail();
} catch (expected) {}; } catch (expected) {};
// Test setOption // Test setOption
helpers.doEx('set testoption=c') helpers.doEx('set testopt=c')
eq('c', CodeMirror.Vim.getOption('testoption')); eq('c', CodeMirror.Vim.getOption('testopt'));
helpers.doEx('set testopt=c')
eq('c', CodeMirror.Vim.getOption('testopt', cm)); //local || global
eq('c', CodeMirror.Vim.getOption('testopt', cm, {scope: 'local'})); // local
eq('c', CodeMirror.Vim.getOption('testopt', cm, {scope: 'global'})); // global
eq('c', CodeMirror.Vim.getOption('testopt')); // global
// Test setOption global
helpers.doEx('setg testopt=d')
eq('c', CodeMirror.Vim.getOption('testopt', cm));
eq('c', CodeMirror.Vim.getOption('testopt', cm, {scope: 'local'}));
eq('d', CodeMirror.Vim.getOption('testopt', cm, {scope: 'global'}));
eq('d', CodeMirror.Vim.getOption('testopt'));
// Test setOption local
helpers.doEx('setl testopt=e')
eq('e', CodeMirror.Vim.getOption('testopt', cm));
eq('e', CodeMirror.Vim.getOption('testopt', cm, {scope: 'local'}));
eq('d', CodeMirror.Vim.getOption('testopt', cm, {scope: 'global'}));
eq('d', CodeMirror.Vim.getOption('testopt'));
});
testVim('ex_set_callback', function(cm, vim, helpers) {
var global;
function cb(val, cm, cfg) {
if (val === undefined) {
// Getter
if (cm) {
return cm._local;
} else {
return global;
}
} else {
// Setter
if (cm) {
cm._local = val;
} else {
global = val;
}
}
}
CodeMirror.Vim.defineOption('testopt', 'a', 'string', cb);
// Test default value is set.
eq('a', CodeMirror.Vim.getOption('testopt'));
try {
// Test fail to set 'notestopt'
helpers.doEx('set notestopt=b');
fail();
} catch (expected) {};
// Test setOption (Identical to the string tests, but via callback instead)
helpers.doEx('set testopt=c')
eq('c', CodeMirror.Vim.getOption('testopt', cm)); //local || global
eq('c', CodeMirror.Vim.getOption('testopt', cm, {scope: 'local'})); // local
eq('c', CodeMirror.Vim.getOption('testopt', cm, {scope: 'global'})); // global
eq('c', CodeMirror.Vim.getOption('testopt')); // global
// Test setOption global
helpers.doEx('setg testopt=d')
eq('c', CodeMirror.Vim.getOption('testopt', cm));
eq('c', CodeMirror.Vim.getOption('testopt', cm, {scope: 'local'}));
eq('d', CodeMirror.Vim.getOption('testopt', cm, {scope: 'global'}));
eq('d', CodeMirror.Vim.getOption('testopt'));
// Test setOption local
helpers.doEx('setl testopt=e')
eq('e', CodeMirror.Vim.getOption('testopt', cm));
eq('e', CodeMirror.Vim.getOption('testopt', cm, {scope: 'local'}));
eq('d', CodeMirror.Vim.getOption('testopt', cm, {scope: 'global'}));
eq('d', CodeMirror.Vim.getOption('testopt'));
})
testVim('ex_set_filetype', function(cm, vim, helpers) {
CodeMirror.defineMode('test_mode', function() {
return {token: function(stream) {
stream.match(/^\s+|^\S+/);
}};
});
CodeMirror.defineMode('test_mode_2', function() {
return {token: function(stream) {
stream.match(/^\s+|^\S+/);
}};
});
// Test mode is set.
helpers.doEx('set filetype=test_mode');
eq('test_mode', cm.getMode().name);
// Test 'ft' alias also sets mode.
helpers.doEx('set ft=test_mode_2');
eq('test_mode_2', cm.getMode().name);
});
testVim('ex_set_filetype_null', function(cm, vim, helpers) {
CodeMirror.defineMode('test_mode', function() {
return {token: function(stream) {
stream.match(/^\s+|^\S+/);
}};
});
cm.setOption('mode', 'test_mode');
// Test mode is set to null.
helpers.doEx('set filetype=');
eq('null', cm.getMode().name);
}); });
// TODO: Reset key maps after each test. // TODO: Reset key maps after each test.
testVim('ex_map_key2key', function(cm, vim, helpers) { testVim('ex_map_key2key', function(cm, vim, helpers) {

View file

@ -120,9 +120,9 @@ var FontMetrics = exports.FontMetrics = function(parentEl, interval) {
this.setPolling = function(val) { this.setPolling = function(val) {
if (val) { if (val) {
this.$pollSizeChanges(); this.$pollSizeChanges();
} else { } else if (this.$pollSizeChangesTimer) {
if (this.$pollSizeChangesTimer) clearInterval(this.$pollSizeChangesTimer);
this.$pollSizeChangesTimer; this.$pollSizeChangesTimer = 0;
} }
}; };

View file

@ -100,16 +100,14 @@ var Gutter = function(parentEl) {
} }
}; };
this.$updateAnnotations = function (e) { this.$updateAnnotations = function (delta) {
if (!this.$annotations.length) if (!this.$annotations.length)
return; return;
var delta = e.data; var firstRow = delta.start.row;
var range = delta.range; var len = delta.end.row - firstRow;
var firstRow = range.start.row;
var len = range.end.row - firstRow;
if (len === 0) { if (len === 0) {
// do nothing // do nothing
} else if (delta.action == "removeText" || delta.action == "removeLines") { } else if (delta.action == 'remove') {
this.$annotations.splice(firstRow, len + 1, null); this.$annotations.splice(firstRow, len + 1, null);
} else { } else {
var args = new Array(len + 1); var args = new Array(len + 1);

View file

@ -90,7 +90,7 @@ var Marker = function(parentEl) {
else else
this.drawMultiLineMarker(html, range, marker.clazz, config); this.drawMultiLineMarker(html, range, marker.clazz, config);
} else { } else {
this.drawSingleLineMarker(html, range, marker.clazz + " ace_start", config); this.drawSingleLineMarker(html, range, marker.clazz + " ace_start" + " ace_br15", config);
} }
} }
this.element.innerHTML = html.join(""); this.element.innerHTML = html.join("");
@ -100,27 +100,30 @@ var Marker = function(parentEl) {
return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight; return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight;
}; };
function getBorderClass(tl, tr, br, bl) {
return (tl ? 1 : 0) | (tr ? 2 : 0) | (br ? 4 : 0) | (bl ? 8 : 0);
}
// Draws a marker, which spans a range of text on multiple lines // Draws a marker, which spans a range of text on multiple lines
this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig, extraStyle) { this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig, extraStyle) {
// selection start var session = this.session;
var row = range.start.row; var start = range.start.row;
var end = range.end.row;
var lineRange = new Range( var row = start;
row, range.start.column, var prev = 0;
row, this.session.getScreenLastRowColumn(row) var curr = 0;
); var next = session.getScreenLastRowColumn(row);
this.drawSingleLineMarker(stringBuilder, lineRange, clazz + " ace_start", layerConfig, 1, extraStyle); var lineRange = new Range(row, range.start.column, row, curr);
for (; row <= end; row++) {
// selection end lineRange.start.row = lineRange.end.row = row;
row = range.end.row; lineRange.start.column = row == start ? range.start.column : session.getRowWrapIndent(row);
lineRange = new Range(row, 0, row, range.end.column); lineRange.end.column = next;
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 0, extraStyle); prev = curr;
curr = next;
for (row = range.start.row + 1; row < range.end.row; row++) { next = row + 1 < end ? session.getScreenLastRowColumn(row + 1) : row == end ? 0 : range.end.column;
lineRange.start.row = row; this.drawSingleLineMarker(stringBuilder, lineRange,
lineRange.end.row = row; clazz + (row == start ? " ace_start" : "") + " ace_br"
lineRange.end.column = this.session.getScreenLastRowColumn(row); + getBorderClass(row == start || row == start + 1 && range.start.column, prev < curr, curr > next, row == end),
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1, extraStyle); layerConfig, row == end ? 0 : 1, extraStyle);
} }
}; };
@ -134,7 +137,7 @@ var Marker = function(parentEl) {
extraStyle = extraStyle || ""; extraStyle = extraStyle || "";
stringBuilder.push( stringBuilder.push(
"<div class='", clazz, " ace_start' style='", "<div class='", clazz, " ace_br1 ace_start' style='",
"height:", height, "px;", "height:", height, "px;",
"right:0;", "right:0;",
"top:", top, "px;", "top:", top, "px;",
@ -146,7 +149,7 @@ var Marker = function(parentEl) {
var width = range.end.column * config.characterWidth; var width = range.end.column * config.characterWidth;
stringBuilder.push( stringBuilder.push(
"<div class='", clazz, "' style='", "<div class='", clazz, " ace_br12' style='",
"height:", height, "px;", "height:", height, "px;",
"width:", width, "px;", "width:", width, "px;",
"top:", top, "px;", "top:", top, "px;",
@ -155,12 +158,14 @@ var Marker = function(parentEl) {
// all the complete lines // all the complete lines
height = (range.end.row - range.start.row - 1) * config.lineHeight; height = (range.end.row - range.start.row - 1) * config.lineHeight;
if (height < 0) if (height <= 0)
return; return;
top = this.$getTop(range.start.row + 1, config); top = this.$getTop(range.start.row + 1, config);
var radiusClass = (range.start.column ? 1 : 0) | (range.end.column ? 0 : 8);
stringBuilder.push( stringBuilder.push(
"<div class='", clazz, "' style='", "<div class='", clazz, (radiusClass ? " ace_br" + radiusClass : ""), "' style='",
"height:", height, "px;", "height:", height, "px;",
"right:0;", "right:0;",
"top:", top, "px;", "top:", top, "px;",

View file

@ -52,7 +52,7 @@ var Text = function(parentEl) {
this.EOL_CHAR_LF = "\xAC"; this.EOL_CHAR_LF = "\xAC";
this.EOL_CHAR_CRLF = "\xa4"; this.EOL_CHAR_CRLF = "\xa4";
this.EOL_CHAR = this.EOL_CHAR_LF; this.EOL_CHAR = this.EOL_CHAR_LF;
this.TAB_CHAR = "\u2192"; //"\u21E5"; this.TAB_CHAR = "\u2014"; //"\u21E5";
this.SPACE_CHAR = "\xB7"; this.SPACE_CHAR = "\xB7";
this.$padding = 0; this.$padding = 0;
@ -128,11 +128,10 @@ var Text = function(parentEl) {
for (var i = 1; i < tabSize + 1; i++) { for (var i = 1; i < tabSize + 1; i++) {
if (this.showInvisibles) { if (this.showInvisibles) {
tabStr.push("<span class='ace_invisible ace_invisible_tab'>" tabStr.push("<span class='ace_invisible ace_invisible_tab'>"
+ this.TAB_CHAR + lang.stringRepeat(this.TAB_CHAR, i)
+ lang.stringRepeat("\xa0", i - 1)
+ "</span>"); + "</span>");
} else { } else {
tabStr.push(lang.stringRepeat("\xa0", i)); tabStr.push(lang.stringRepeat(" ", i));
} }
} }
if (this.displayIndentGuides) { if (this.displayIndentGuides) {
@ -145,9 +144,9 @@ var Text = function(parentEl) {
spaceClass = " ace_invisible_space"; spaceClass = " ace_invisible_space";
tabClass = " ace_invisible_tab"; tabClass = " ace_invisible_tab";
var spaceContent = lang.stringRepeat(this.SPACE_CHAR, this.tabSize); var spaceContent = lang.stringRepeat(this.SPACE_CHAR, this.tabSize);
var tabContent = this.TAB_CHAR + lang.stringRepeat("\xa0", this.tabSize - 1); var tabContent = lang.stringRepeat(this.TAB_CHAR, this.tabSize);
} else{ } else{
var spaceContent = lang.stringRepeat("\xa0", this.tabSize); var spaceContent = lang.stringRepeat(" ", this.tabSize);
var tabContent = spaceContent; var tabContent = spaceContent;
} }
@ -325,9 +324,9 @@ var Text = function(parentEl) {
var replaceReg = /\t|&|<|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g; var replaceReg = /\t|&|<|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g;
var replaceFunc = function(c, a, b, tabIdx, idx4) { var replaceFunc = function(c, a, b, tabIdx, idx4) {
if (a) { if (a) {
return self.showInvisibles ? return self.showInvisibles
"<span class='ace_invisible ace_invisible_space'>" + lang.stringRepeat(self.SPACE_CHAR, c.length) + "</span>" : ? "<span class='ace_invisible ace_invisible_space'>" + lang.stringRepeat(self.SPACE_CHAR, c.length) + "</span>"
lang.stringRepeat("\xa0", c.length); : c;
} else if (c == "&") { } else if (c == "&") {
return "&#38;"; return "&#38;";
} else if (c == "<") { } else if (c == "<") {
@ -420,6 +419,8 @@ var Text = function(parentEl) {
); );
} }
stringBuilder.push(lang.stringRepeat("\xa0", splits.indent));
split ++; split ++;
screenColumn = 0; screenColumn = 0;
splitChars = splits[split] || Number.MAX_VALUE; splitChars = splits[split] || Number.MAX_VALUE;

View file

@ -89,9 +89,9 @@ module.exports = {
"test rendering of indent guides" : function() { "test rendering of indent guides" : function() {
var textLayer = this.textLayer var textLayer = this.textLayer
var EOL = "<span class='ace_invisible ace_invisible_eol'>" + textLayer.EOL_CHAR + "</span>"; var EOL = "<span class='ace_invisible ace_invisible_eol'>" + textLayer.EOL_CHAR + "</span>";
var SPACE = function(i) {return Array(i+1).join("\xa0")} var SPACE = function(i) {return Array(i+1).join(" ")}
var DOT = function(i) {return Array(i+1).join(textLayer.SPACE_CHAR)} var DOT = function(i) {return Array(i+1).join(textLayer.SPACE_CHAR)}
var TAB = function(i) {return textLayer.TAB_CHAR + SPACE(i-1)} var TAB = function(i) {return Array(i+1).join(textLayer.TAB_CHAR)}
function testRender(results) { function testRender(results) {
for (var i = results.length; i--; ) { for (var i = results.length; i--; ) {
var stringBuilder = []; var stringBuilder = [];

View file

@ -91,6 +91,11 @@ exports.toggleCssClass = function(el, name) {
return add; return add;
}; };
if (typeof document == "undefined") {
exports.importCssString = function() {};
return;
}
/* /*
* Add or remove a CSS class from the list of classes on the given node * Add or remove a CSS class from the list of classes on the given node
* depending on the value of <tt>include</tt> * depending on the value of <tt>include</tt>
@ -173,9 +178,6 @@ exports.getInnerHeight = function(element) {
}; };
if (typeof document == "undefined")
return;
if (window.pageYOffset !== undefined) { if (window.pageYOffset !== undefined) {
exports.getPageScrollTop = function() { exports.getPageScrollTop = function() {
return window.pageYOffset; return window.pageYOffset;

View file

@ -244,7 +244,7 @@ function normalizeCommandKeys(callback, e, keyCode) {
if (pressedKeys[keyCode] == 1) if (pressedKeys[keyCode] == 1)
ts = e.timeStamp; ts = e.timeStamp;
} else if (keyCode === 18 && hashId === 3 && location === 2) { } else if (keyCode === 18 && hashId === 3 && location === 2) {
var dt = e.timestamp - ts; var dt = e.timeStamp - ts;
if (dt < 50) if (dt < 50)
pressedKeys.altGr = true; pressedKeys.altGr = true;
} }
@ -326,13 +326,14 @@ exports.addCommandKeyListener = function(el, callback) {
}); });
if (!pressedKeys) { if (!pressedKeys) {
pressedKeys = Object.create(null); resetPressedKeys();
addListener(window, "focus", function(e) { addListener(window, "focus", resetPressedKeys);
pressedKeys = Object.create(null);
});
} }
} }
}; };
function resetPressedKeys(e) {
pressedKeys = Object.create(null);
}
if (window.postMessage && !useragent.isOldIE) { if (window.postMessage && !useragent.isOldIE) {
var postMessageId = 1; var postMessageId = 1;

View file

@ -104,8 +104,8 @@ var Keys = (function() {
73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o', 73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o',
80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v', 80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v',
87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.', 87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.',
187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`', 219: '[', 186: ';', 187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`',
220: '\\',221: ']', 222: '\'' 219: '[', 220: '\\',221: ']', 222: '\''
} }
}; };

View file

@ -81,20 +81,24 @@ exports.copyArray = function(array){
return copy; return copy;
}; };
exports.deepCopy = function (obj) { exports.deepCopy = function deepCopy(obj) {
if (typeof obj !== "object" || !obj) if (typeof obj !== "object" || !obj)
return obj; return obj;
var copy;
if (Array.isArray(obj)) {
copy = [];
for (var key = 0; key < obj.length; key++) {
copy[key] = deepCopy(obj[key]);
}
return copy;
}
var cons = obj.constructor; var cons = obj.constructor;
if (cons === RegExp) if (cons === RegExp)
return obj; return obj;
var copy = cons(); copy = cons();
for (var key in obj) { for (var key in obj) {
if (typeof obj[key] === "object") { copy[key] = deepCopy(obj[key]);
copy[key] = exports.deepCopy(obj[key]);
} else {
copy[key] = obj[key];
}
} }
return copy; return copy;
}; };

View file

@ -113,18 +113,16 @@ function LineWidgets(session) {
}); });
}; };
this.updateOnChange = function(e) { this.updateOnChange = function(delta) {
var lineWidgets = this.session.lineWidgets; var lineWidgets = this.session.lineWidgets;
if (!lineWidgets) return; if (!lineWidgets) return;
var delta = e.data; var startRow = delta.start.row;
var range = delta.range; var len = delta.end.row - startRow;
var startRow = range.start.row;
var len = range.end.row - startRow;
if (len === 0) { if (len === 0) {
// return // return
} else if (delta.action == "removeText" || delta.action == "removeLines") { } else if (delta.action == 'remove') {
var removed = lineWidgets.splice(startRow + 1, len); var removed = lineWidgets.splice(startRow + 1, len);
removed.forEach(function(w) { removed.forEach(function(w) {
w && this.removeLineWidget(w); w && this.removeLineWidget(w);

View file

@ -56,34 +56,34 @@
],[ ],[
"start", "start",
["text"," "], ["text"," "],
["comment","| "], ["comment","|"],
["string","start "], ["string"," start "],
["comment","| "], ["comment","|"],
["string","eat "], ["string"," eat "],
["comment","| "], ["comment","|"],
["string","left "], ["string"," left "],
["comment","|"] ["comment","|"]
],[ ],[
"start", "start",
["text"," "], ["text"," "],
["comment","| "], ["comment","|"],
["string"," 12 "], ["string"," 12 "],
["comment","| "], ["comment","|"],
["string"," 5 "], ["string"," 5 "],
["comment","| "], ["comment","|"],
["string"," 7 "], ["string"," 7 "],
["comment","|"] ["comment","|"]
],[ ],[
"start", "start",
["text"," "], ["text"," "],
["comment","| "], ["comment","|"],
["string"," 20 "], ["string"," 20 "],
["comment","| "], ["comment","|"],
["string"," 5 "], ["string"," 5 "],
["comment","| "], ["comment","|"],
["string"," 15 "], ["string"," 15 "],
["comment","| "], ["comment","|"],
["string"," "] ["string"," "]
],[ ],[
"start" "start"
],[ ],[

View file

@ -10,10 +10,9 @@
],[ ],[
"start", "start",
["keyword.source.rust","fn"], ["keyword.source.rust","fn"],
["meta.function.source.rust"," "], ["text"," "],
["entity.name.function.source.rust","main"], ["entity.name.function.source.rust","main"],
["meta.function.source.rust","("], ["text","() {"]
["text",") {"]
],[ ],[
"start", "start",
["text"," "], ["text"," "],
@ -88,10 +87,14 @@
],[ ],[
"start", "start",
["keyword.source.rust","fn"], ["keyword.source.rust","fn"],
["meta.function.source.rust"," "], ["text"," "],
["entity.name.function.source.rust","map<T, U>"], ["entity.name.function.source.rust","map"],
["meta.function.source.rust","("], ["keyword.operator","<"],
["text","vector: &[T]"], ["text","T"],
["keyword.operator",","],
["text"," U"],
["keyword.operator",">"],
["text","(vector: &[T]"],
["keyword.operator",","], ["keyword.operator",","],
["text"," function: &fn(v: &T) "], ["text"," function: &fn(v: &T) "],
["keyword.operator","->"], ["keyword.operator","->"],

View file

@ -199,7 +199,5 @@
["string.quoted.double.asp"," ... updated.\""] ["string.quoted.double.asp"," ... updated.\""]
],[ ],[
"start", "start",
["support.function.asp","End"], ["storage.type.asp","End Sub"]
["text"," "],
["storage.type.asp","Sub"]
]] ]]

View file

@ -144,6 +144,16 @@ module.exports = {
exec("selectleft", 1); exec("selectleft", 1);
exec("insertstring", 1, '"'); exec("insertstring", 1, '"');
assert.equal(editor.getValue(), '("foo")'); assert.equal(editor.getValue(), '("foo")');
editor.setValue("", 1);
exec("selectleft", 1);
exec("insertstring", 1, '"');
assert.equal(editor.getValue(), '""');
exec("insertstring", 1, '\\');
exec("insertstring", 1, 'n');
exec("insertstring", 1, '"');
assert.equal(editor.getValue(), '"\\n"');
}, },
"test: xml": function() { "test: xml": function() {
editor = new Editor(new MockRenderer()); editor = new Editor(new MockRenderer());

View file

@ -63,6 +63,19 @@ var initContext = function(editor) {
}; };
}; };
var getWrapped = function(selection, selected, opening, closing) {
var rowDiff = selection.end.row - selection.start.row;
return {
text: opening + selected + closing,
selection: [
0,
selection.start.column + 1,
rowDiff,
selection.end.column + (rowDiff ? 0 : 1)
]
};
};
var CstyleBehaviour = function() { var CstyleBehaviour = function() {
this.add("braces", "insertion", function(state, action, editor, session, text) { this.add("braces", "insertion", function(state, action, editor, session, text) {
var cursor = editor.getCursorPosition(); var cursor = editor.getCursorPosition();
@ -72,10 +85,7 @@ var CstyleBehaviour = function() {
var selection = editor.getSelectionRange(); var selection = editor.getSelectionRange();
var selected = session.doc.getTextRange(selection); var selected = session.doc.getTextRange(selection);
if (selected !== "" && selected !== "{" && editor.getWrapBehavioursEnabled()) { if (selected !== "" && selected !== "{" && editor.getWrapBehavioursEnabled()) {
return { return getWrapped(selection, selected, '{', '}');
text: '{' + selected + '}',
selection: false
};
} else if (CstyleBehaviour.isSaneInsertion(editor, session)) { } else if (CstyleBehaviour.isSaneInsertion(editor, session)) {
if (/[\]\}\)]/.test(line[cursor.column]) || editor.inMultiSelectMode) { if (/[\]\}\)]/.test(line[cursor.column]) || editor.inMultiSelectMode) {
CstyleBehaviour.recordAutoInsert(editor, session, "}"); CstyleBehaviour.recordAutoInsert(editor, session, "}");
@ -155,10 +165,7 @@ var CstyleBehaviour = function() {
var selection = editor.getSelectionRange(); var selection = editor.getSelectionRange();
var selected = session.doc.getTextRange(selection); var selected = session.doc.getTextRange(selection);
if (selected !== "" && editor.getWrapBehavioursEnabled()) { if (selected !== "" && editor.getWrapBehavioursEnabled()) {
return { return getWrapped(selection, selected, '(', ')');
text: '(' + selected + ')',
selection: false
};
} else if (CstyleBehaviour.isSaneInsertion(editor, session)) { } else if (CstyleBehaviour.isSaneInsertion(editor, session)) {
CstyleBehaviour.recordAutoInsert(editor, session, ")"); CstyleBehaviour.recordAutoInsert(editor, session, ")");
return { return {
@ -203,10 +210,7 @@ var CstyleBehaviour = function() {
var selection = editor.getSelectionRange(); var selection = editor.getSelectionRange();
var selected = session.doc.getTextRange(selection); var selected = session.doc.getTextRange(selection);
if (selected !== "" && editor.getWrapBehavioursEnabled()) { if (selected !== "" && editor.getWrapBehavioursEnabled()) {
return { return getWrapped(selection, selected, '[', ']');
text: '[' + selected + ']',
selection: false
};
} else if (CstyleBehaviour.isSaneInsertion(editor, session)) { } else if (CstyleBehaviour.isSaneInsertion(editor, session)) {
CstyleBehaviour.recordAutoInsert(editor, session, "]"); CstyleBehaviour.recordAutoInsert(editor, session, "]");
return { return {
@ -252,10 +256,7 @@ var CstyleBehaviour = function() {
var selection = editor.getSelectionRange(); var selection = editor.getSelectionRange();
var selected = session.doc.getTextRange(selection); var selected = session.doc.getTextRange(selection);
if (selected !== "" && selected !== "'" && selected != '"' && editor.getWrapBehavioursEnabled()) { if (selected !== "" && selected !== "'" && selected != '"' && editor.getWrapBehavioursEnabled()) {
return { return getWrapped(selection, selected, quote, quote);
text: quote + selected + quote,
selection: false
};
} else if (!selected) { } else if (!selected) {
var cursor = editor.getCursorPosition(); var cursor = editor.getCursorPosition();
var line = session.doc.getLine(cursor.row); var line = session.doc.getLine(cursor.row);
@ -268,8 +269,8 @@ var CstyleBehaviour = function() {
if (leftChar == "\\" && token && /escape/.test(token.type)) if (leftChar == "\\" && token && /escape/.test(token.type))
return null; return null;
var stringBefore = token && /string/.test(token.type); var stringBefore = token && /string|escape/.test(token.type);
var stringAfter = !rightToken || /string/.test(rightToken.type); var stringAfter = !rightToken || /string|escape/.test(rightToken.type);
var pair; var pair;
if (rightChar == quote) { if (rightChar == quote) {

View file

@ -53,7 +53,7 @@ oop.inherits(FoldMode, BaseFoldMode);
this.foldingStopMarker = /^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/; this.foldingStopMarker = /^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/;
this.singleLineBlockCommentRe= /^\s*(\/\*).*\*\/\s*$/; this.singleLineBlockCommentRe= /^\s*(\/\*).*\*\/\s*$/;
this.tripleStarBlockCommentRe = /^\s*(\/\*\*\*).*\*\/\s*$/; this.tripleStarBlockCommentRe = /^\s*(\/\*\*\*).*\*\/\s*$/;
this.startRegionRe = /^\s*(\/\*|\/\/)#region\b/; this.startRegionRe = /^\s*(\/\*|\/\/)#?region\b/;
//prevent naming conflict with any modes that inherit from cstyle and override this (like csharp) //prevent naming conflict with any modes that inherit from cstyle and override this (like csharp)
this._getFoldWidgetBase = this.getFoldWidget; this._getFoldWidgetBase = this.getFoldWidget;
@ -69,6 +69,8 @@ oop.inherits(FoldMode, BaseFoldMode);
* *
* @example tripleStarFoldingSection * @example tripleStarFoldingSection
* /*** this folds even though 1 line because it has 3 stars ***[/] * /*** this folds even though 1 line because it has 3 stars ***[/]
*
* @note the pound symbol for region tags is optional
*/ */
this.getFoldWidget = function(session, foldStyle, row) { this.getFoldWidget = function(session, foldStyle, row) {
var line = session.getLine(row); var line = session.getLine(row);
@ -158,12 +160,16 @@ oop.inherits(FoldMode, BaseFoldMode);
return new Range(startRow, startColumn, endRow, session.getLine(endRow).length); return new Range(startRow, startColumn, endRow, session.getLine(endRow).length);
}; };
/**
* gets comment region block with end region assumed to be start of comment in any cstyle mode or SQL mode (--) which inherits from this.
* There may optionally be a pound symbol before the region/endregion statement
*/
this.getCommentRegionBlock = function(session, line, row) { this.getCommentRegionBlock = function(session, line, row) {
var startColumn = line.search(/\s*$/); var startColumn = line.search(/\s*$/);
var maxRow = session.getLength(); var maxRow = session.getLength();
var startRow = row; var startRow = row;
var re = /^\s*(?:\/\*|\/\/)#(end)?region\b/; var re = /^\s*(?:\/\*|\/\/|--)#?(end)?region\b/;
var depth = 1; var depth = 1;
while (++row < maxRow) { while (++row < maxRow) {
line = session.getLine(row); line = session.getLine(row);

View file

@ -0,0 +1,111 @@
/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2010, Ajax.org B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var oop = require("../../lib/oop");
var Range = require("../../range").Range;
var BaseFoldMode = require("./cstyle").FoldMode;
var FoldMode = exports.FoldMode = function() {};
oop.inherits(FoldMode, BaseFoldMode);
(function() {
/**
* Inheriting cstyle folding because it handles the region comment folding
* and special block comment folding appropriately.
*
* Cstyle's getCommentRegionBlock() contains the sql comment characters '--' for end region block.
*/
this.foldingStartMarker = /(\bCASE\b|\bBEGIN\b)|^\s*(\/\*)/i;
// this.foldingStopMarker = /(\bEND\b)|^[\s\*]*(\*\/)/i;
this.startRegionRe = /^\s*(\/\*|--)#?region\b/;
this.getFoldWidgetRange = function(session, foldStyle, row, forceMultiline) {
var line = session.getLine(row);
if (this.startRegionRe.test(line)) return this.getCommentRegionBlock(session, line, row);
var match = line.match(this.foldingStartMarker);
if (match) {
var i = match.index;
if (match[1]) return this.getBeginEndBlock(session, row, i, match[1]);
var range = session.getCommentFoldRange(row, i + match[0].length, 1);
if (range && !range.isMultiLine()) {
if (forceMultiline) {
range = this.getSectionRange(session, row);
}
else if (foldStyle != "all") range = null;
}
return range;
}
if (foldStyle === "markbegin") return;
//TODO: add support for end folding markers
return;
};
/**
* @returns {range} folding block for sequence that starts with 'CASE' or 'BEGIN' and ends with 'END'
* @param {string} matchSequence - the sequence of charaters that started the fold widget, which should remain visible when the fold widget is folded
*/
this.getBeginEndBlock = function(session, row, column, matchSequence) {
var start = {
row: row,
column: column + matchSequence.length
};
var maxRow = session.getLength();
var line;
var depth = 1;
var re = /(\bCASE\b|\bBEGIN\b)|(\bEND\b)/i;
while (++row < maxRow) {
line = session.getLine(row);
var m = re.exec(line);
if (!m) continue;
if (m[1]) depth++;
else depth--;
if (!depth) break;
}
var endRow = row;
if (endRow > start.row) {
return new Range(start.row, start.column, endRow, line.length);
}
};
}).call(FoldMode.prototype);
});

View file

@ -36,18 +36,18 @@ var stringEscape = "\\\\(x[0-9A-Fa-f]{2}|[0-7]{3}|[\\\\abfnrtv'\"]|U[0-9A-Fa-f]
var GherkinHighlightRules = function() { var GherkinHighlightRules = function() {
// need to include constant ints // need to include constant ints
this.$rules = { this.$rules = {
start : [{ start : [{
token: 'constant.numeric', token: 'constant.numeric',
regex: "(?:(?:[1-9]\\d*)|(?:0))" regex: "(?:(?:[1-9]\\d*)|(?:0))"
}, { }, {
token : "comment", token : "comment",
regex : "#.*$" regex : "#.*$"
}, { }, {
token : "keyword", token : "keyword",
regex : "Feature:|Background:|Scenario:|Scenario\ Outline:|Examples:|Given|When|Then|And|But|\\*", regex : "Feature:|Background:|Scenario:|Scenario\ Outline:|Examples:|Given|When|Then|And|But|\\*",
}, { }, {
token : "string", // multi line """ string start token : "string", // multi line """ string start
regex : '"{3}', regex : '"{3}',
next : "qqstring3" next : "qqstring3"
@ -56,22 +56,22 @@ var GherkinHighlightRules = function() {
regex : '"', regex : '"',
next : "qqstring" next : "qqstring"
}, { }, {
token : "comment", token : "comment",
regex : "@[A-Za-z0-9]+", regex : "@[A-Za-z0-9]+",
next : "start" next : "start"
}, { }, {
token : "comment", token : "comment",
regex : "<.+>" regex : "<.+>"
}, { }, {
token : "comment", token : "comment",
regex : "\\| ", regex : "\\|(?=.)",
next : "table-item" next : "table-item"
}, { }, {
token : "comment", token : "comment",
regex : "\\|$", regex : "\\|$",
next : "start" next : "start"
}], }],
"qqstring3" : [ { "qqstring3" : [ {
token : "constant.language.escape", token : "constant.language.escape",
regex : stringEscape regex : stringEscape
}, { }, {
@ -81,7 +81,7 @@ var GherkinHighlightRules = function() {
}, { }, {
defaultToken : "string" defaultToken : "string"
}], }],
"qqstring" : [{ "qqstring" : [{
token : "constant.language.escape", token : "constant.language.escape",
regex : stringEscape regex : stringEscape
}, { }, {
@ -96,15 +96,19 @@ var GherkinHighlightRules = function() {
defaultToken: "string" defaultToken: "string"
}], }],
"table-item" : [{ "table-item" : [{
token : "comment",
regex : /$/,
next : "start"
}, {
token : "comment",
regex : /\|/
}, {
token : "string", token : "string",
regex : "[A-Za-z0-9 ]*", regex : /\\./
next : "start" }, {
}], defaultToken : "string"
}]
}; };
//new TextHighlightRules().getRules();
} }
oop.inherits(GherkinHighlightRules, TextHighlightRules); oop.inherits(GherkinHighlightRules, TextHighlightRules);

View file

@ -13,7 +13,6 @@ var Mode = function() {
HtmlMode.call(this); HtmlMode.call(this);
this.HighlightRules = HandlebarsHighlightRules; this.HighlightRules = HandlebarsHighlightRules;
this.$behaviour = new HtmlBehaviour(); this.$behaviour = new HtmlBehaviour();
this.foldingRules = new HtmlFoldMode(); this.foldingRules = new HtmlFoldMode();
}; };
@ -21,7 +20,7 @@ var Mode = function() {
oop.inherits(Mode, HtmlMode); oop.inherits(Mode, HtmlMode);
(function() { (function() {
this.blockComment = {start: "{!--", end: "--}"}; this.blockComment = {start: "{{!--", end: "--}}"};
this.$id = "ace/mode/handlebars"; this.$id = "ace/mode/handlebars";
}).call(Mode.prototype); }).call(Mode.prototype);

View file

@ -65,7 +65,7 @@ var HtmlHighlightRules = function() {
include : "tag_whitespace" include : "tag_whitespace"
}, { }, {
token : "entity.other.attribute-name.xml", token : "entity.other.attribute-name.xml",
regex : "[-_a-zA-Z0-9:]+" regex : "[-_a-zA-Z0-9:.]+"
}, { }, {
token : "keyword.operator.attribute-equals.xml", token : "keyword.operator.attribute-equals.xml",
regex : "=", regex : "=",
@ -89,7 +89,7 @@ var HtmlHighlightRules = function() {
return ["meta.tag.punctuation." + (start == "<" ? "" : "end-") + "tag-open.xml", return ["meta.tag.punctuation." + (start == "<" ? "" : "end-") + "tag-open.xml",
"meta.tag" + (group ? "." + group : "") + ".tag-name.xml"]; "meta.tag" + (group ? "." + group : "") + ".tag-name.xml"];
}, },
regex : "(</?)([-_a-zA-Z0-9:]+)", regex : "(</?)([-_a-zA-Z0-9:.]+)",
next: "tag_stuff" next: "tag_stuff"
}], }],
tag_stuff: [ tag_stuff: [

File diff suppressed because it is too large Load diff

View file

@ -231,7 +231,7 @@ var LessHighlightRules = function() {
regex: "\\.[a-z0-9-_]+" regex: "\\.[a-z0-9-_]+"
}, { }, {
token: "variable.language", token: "variable.language",
regex: ":[a-z0-9-_]+" regex: ":[a-z_][a-z0-9-_]*"
}, { }, {
token: "constant", token: "constant",
regex: "[a-z0-9-_]+" regex: "[a-z0-9-_]+"

113
lib/ace/mode/nim.js Normal file
View file

@ -0,0 +1,113 @@
/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2010, Ajax.org B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var TextMode = require("./text").Mode;
var NimHighlightRules = require("./nim_highlight_rules").NimHighlightRules;
var NimFoldMode = require("./folding/pythonic").FoldMode;
var Range = require("../range").Range;
var Mode = function() {
this.HighlightRules = NimHighlightRules;
this.foldingRules = new NimFoldMode("\\:|=");
};
oop.inherits(Mode, TextMode);
(function() {
this.lineCommentStart = "#";
this.getNextLineIndent = function(state, line, tab) {
var indent = this.$getIndent(line);
var tokenizedLine = this.getTokenizer().getLineTokens(line, state);
var tokens = tokenizedLine.tokens;
if (tokens.length && tokens[tokens.length-1].type == "comment") {
return indent;
}
if (state == "start") {
var match = line.match(/^.*[\{\(\[\:=]\s*$/);
if (match) {
indent += tab;
}
}
return indent;
};
var outdents = {
"discard": 1,
"return": 1,
"raise": 1,
"break": 1,
"continue": 1
};
this.checkOutdent = function(state, line, input) {
if (input !== "\r\n" && input !== "\r" && input !== "\n")
return false;
var tokens = this.getTokenizer().getLineTokens(line.trim(), state).tokens;
if (!tokens)
return false;
// ignore trailing comments
do {
var last = tokens.pop();
} while (last && (last.type == "comment" || (last.type == "text" && last.value.match(/^\s+$/))));
if (!last)
return false;
return (last.type == "keyword" && outdents[last.value]);
};
this.autoOutdent = function(state, doc, row) {
// outdenting in python is slightly different because it always applies
// to the next line and only of a new line is inserted
row += 1;
var indent = this.$getIndent(doc.getLine(row));
var tab = doc.getTabString();
if (indent.slice(-tab.length) == tab)
doc.remove(new Range(row, indent.length-tab.length, row, indent.length));
};
this.$id = "ace/mode/nim";
}).call(Mode.prototype);
exports.Mode = Mode;
});

View file

@ -0,0 +1,238 @@
/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2010, Ajax.org B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
/*
* TODO: nim delimiters
*/
define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var num_suffix = "(\'[Ff]32|\'[Ff]64|\'[IiUu]8|\'[IiUu]16|\'[IiUu]32|\'[IiUu]64)";
var NimHighlightRules = function() {
var keywords = (
"addr|and|as|asm|atomic|bind|block|break|case|cast|const|continue|" +
"converter|defer|discard|distinct|div|do|elif|else|end|enum|except|" +
"export|finally|for|from|func|generic|if|import|in|include|interface|" +
"is|isnot|iterator|let|macro|method|mixin|mod|nil|not|notin|object|of|" +
"or|out|proc|ptr|raise|ref|return|shl|shr|static|template|try|tuple|" +
"type|using|var|when|while|with|without|xor|yield"
);
var builtinConstants = (
"true|false|nil|NotImplemented|Ellipsis"
);
var storageType = (
"string|seq|array|expr|stmt|typed|untyped|any|auto|bool|cdouble|cfloat|"+
"cchar|clongdouble|clong|clonglong|cshort|csize|cstring|cstringarray|"+
"culong|culonglong|cushort|guarded|natural|openarray|ordinal|pointer|"+
"range|set|shared|static|typedesc|varargs|void"
);
var builtinFunctions = (
"defined|declared|declaredInScope|echo|$"
);
//var futureReserved = "";
var keywordMapper = this.createKeywordMapper({
"invalid.deprecated": "debugger",
"support.function": builtinFunctions,
//"invalid.illegal": futureReserved,
"constant.language": builtinConstants,
"storage.type" : storageType,
"keyword": keywords
}, "identifier");
var strPre = "(?:r|R)?";
var decimalInteger = "(?:(?:[1-9]\\d*)|(?:0))";
var octInteger = "(?:0[o]?[0-7]+)";
var hexInteger = "(?:0[xX][\\dA-Fa-f]+)";
var binInteger = "(?:0[bB][01]+)";
var integer = "(?:" + decimalInteger + "|" + octInteger + "|" + hexInteger + "|" + binInteger + ")";
var exponent = "(?:[eE][+-]?\\d+)";
var fraction = "(?:\\.\\d+)";
var intPart = "(?:\\d+)";
var pointFloat = "(?:(?:" + intPart + "?" + fraction + ")|(?:" + intPart + "\\.))";
var exponentFloat = "(?:(?:" + pointFloat + "|" + intPart + ")" + exponent + ")";
var floatNumber = "(?:" + exponentFloat + "|" + pointFloat + ")";
var stringEscape = "\\\\(x[0-9A-Fa-f]{2}|[0-7]{3}|[\\\\abfnrtv'\"]|U[0-9A-Fa-f]{8}|u[0-9A-Fa-f]{4})";
this.$rules = {
"start" : [ {
token : "comment",
regex : "#.*$"
}, {
token : "keyword",
regex : "(proc|method|temdplate|macro|macromethod|converter|func|iterator) ",
next : "qproc_name"
}, {
token : "storage.type",
regex : "(c|cu|u)?int(8|16|32|64)?",
}, {
token : "storage.type",
regex : "(c|cu|u|cs)?char",
}, {
token : "storage.type",
regex : "float(32|64)?",
}, {
token : "docstring",
regex : "##.*$"
}, {
token : "string", // multi line """ string start
regex : strPre + '"{3}',
next : "qqstring3"
}, {
token : "string", // " string
regex : strPre + '"(?=.)',
next : "qqstring"
}, {
token : "string", // multi line ''' string start
regex : strPre + "'{3}",
next : "qstring3"
}, {
token : "backtick", // ` string
regex : strPre + "`(?=.)",
next : "qxstring"
}, {
token : "string", // ' string
regex : strPre + "'(?=.)",
next : "qstring"
}, {
token : "constant.numeric", // imaginary
regex : "(?:" + floatNumber + "|\\d+)[jJ]\\b"
}, {
token : "constant.numeric", // float
regex : floatNumber
}, {
token : "constant.numeric", // long integer
regex : integer + "[lL]\\b"
}, {
token : "constant.numeric", // integer
regex : integer + "\\b"
}, {
token : keywordMapper,
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "\\+|\\-|\\*|\\*\\*|\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|="
}, {
token : "paren.lparen",
regex : "[\\[\\(\\{]"
}, {
token : "paren.rparen",
regex : "[\\]\\)\\}]"
}, {
token : "text",
regex : "\\s+"
} ],
"qqstring3" : [ {
token : "constant.language.escape",
regex : stringEscape
}, {
token : "string", // multi line """ string end
regex : '"{3}',
next : "start"
}, {
defaultToken : "string"
} ],
"qstring3" : [ {
token : "constant.language.escape",
regex : stringEscape
}, {
token : "string", // multi line ''' string end
regex : "'{3}",
next : "start"
}, {
defaultToken : "string"
} ],
"qqstring" : [{
token : "constant.language.escape",
regex : stringEscape
}, {
token : "string",
regex : "\\\\$",
next : "qqstring"
}, {
token : "string",
regex : '"|$',
next : "start"
}, {
defaultToken: "string"
}],
"qstring" : [{
token : "constant.language.escape",
regex : stringEscape
}, {
token : "string",
regex : "\\\\$",
next : "qstring"
}, {
token : "string",
regex : "'|$",
next : "start"
}, {
defaultToken: "string"
}],
"qxstring" : [{
token : "constant.language.escape",
regex : stringEscape
}, {
token : "backtick",
regex : "\\\\$",
next : "qxstring"
}, {
token : "backtick",
regex : "`|$",
next : "start"
}, {
defaultToken: "backtick"
}],
"qproc_name":[{
token : "proc_name",
regex : "\\w+",
},{
token : "start_bracket",
regex : "(\\(|=|$)",
next : "start"
}],
};
};
oop.inherits(NimHighlightRules, TextHighlightRules);
exports.NimHighlightRules = NimHighlightRules;
});

View file

@ -36,6 +36,7 @@ define(function(require, exports, module) {
var oop = require("../lib/oop"); var oop = require("../lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var stringEscape = /\\(?:[nrt0'"]|x[\da-fA-F]{2}|u\{[\da-fA-F]{6}\})/.source;
var RustHighlightRules = function() { var RustHighlightRules = function() {
// regexp must not have capturing parentheses. Use (?:) instead. // regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used // regexps are ordered -> the first match is used
@ -44,13 +45,7 @@ var RustHighlightRules = function() {
[ { token: 'variable.other.source.rust', [ { token: 'variable.other.source.rust',
regex: '\'[a-zA-Z_][a-zA-Z0-9_]*[^\\\']' }, regex: '\'[a-zA-Z_][a-zA-Z0-9_]*[^\\\']' },
{ token: 'string.quoted.single.source.rust', { token: 'string.quoted.single.source.rust',
regex: '\'', regex: "'(?:[^'\\\\]|" + stringEscape + ")'" },
push:
[ { token: 'string.quoted.single.source.rust',
regex: '\'',
next: 'pop' },
{ include: '#rust_escaped_character' },
{ defaultToken: 'string.quoted.single.source.rust' } ] },
{ {
stateName: "bracketedComment", stateName: "bracketedComment",
onMatch : function(value, currentState, stack){ onMatch : function(value, currentState, stack){
@ -86,14 +81,14 @@ var RustHighlightRules = function() {
[ { token: 'string.quoted.double.source.rust', [ { token: 'string.quoted.double.source.rust',
regex: '"', regex: '"',
next: 'pop' }, next: 'pop' },
{ include: '#rust_escaped_character' }, { token: 'constant.character.escape.source.rust',
regex: stringEscape },
{ defaultToken: 'string.quoted.double.source.rust' } ] }, { defaultToken: 'string.quoted.double.source.rust' } ] },
{ token: [ 'keyword.source.rust', 'meta.function.source.rust', { token: [ 'keyword.source.rust', 'text', 'entity.name.function.source.rust' ],
'entity.name.function.source.rust', 'meta.function.source.rust' ], regex: '\\b(fn)(\\s+)([a-zA-Z_][a-zA-Z0-9_]*)' },
regex: '\\b(fn)(\\s+)([a-zA-Z_][a-zA-Z0-9_][\\w\\:,+ \\\'<>]*)(\\s*\\()' },
{ token: 'support.constant', regex: '\\b[a-zA-Z_][\\w\\d]*::' }, { token: 'support.constant', regex: '\\b[a-zA-Z_][\\w\\d]*::' },
{ token: 'keyword.source.rust', { token: 'keyword.source.rust',
regex: '\\b(?:as|assert|break|claim|const|copy|Copy|do|drop|else|extern|fail|for|if|impl|in|let|log|loop|match|mod|module|move|mut|Owned|priv|pub|pure|ref|return|unchecked|unsafe|use|while|mod|Send|static|trait|class|struct|enum|type)\\b' }, regex: '\\b(?:as|assert|break|claim|const|do|drop|else|extern|fail|for|if|impl|in|let|log|loop|match|mod|module|move|mut|Owned|priv|pub|pure|ref|return|unchecked|unsafe|use|while|mod|Send|static|trait|class|struct|enum|type)\\b' },
{ token: 'storage.type.source.rust', { token: 'storage.type.source.rust',
regex: '\\b(?:Self|m32|m64|m128|f80|f16|f128|int|uint|isize|usize|float|char|bool|u8|u16|u32|u64|f32|f64|i8|i16|i32|i64|str|option|either|c_float|c_double|c_void|FILE|fpos_t|DIR|dirent|c_char|c_schar|c_uchar|c_short|c_ushort|c_int|c_uint|c_long|c_ulong|size_t|ptrdiff_t|clock_t|time_t|c_longlong|c_ulonglong|intptr_t|uintptr_t|off_t|dev_t|ino_t|pid_t|mode_t|ssize_t)\\b' }, regex: '\\b(?:Self|m32|m64|m128|f80|f16|f128|int|uint|isize|usize|float|char|bool|u8|u16|u32|u64|f32|f64|i8|i16|i32|i64|str|option|either|c_float|c_double|c_void|FILE|fpos_t|DIR|dirent|c_char|c_schar|c_uchar|c_short|c_ushort|c_int|c_uint|c_long|c_ulong|size_t|ptrdiff_t|clock_t|time_t|c_longlong|c_ulonglong|intptr_t|uintptr_t|off_t|dev_t|ino_t|pid_t|mode_t|ssize_t)\\b' },
{ token: 'variable.language.source.rust', regex: '\\bself\\b' }, { token: 'variable.language.source.rust', regex: '\\bself\\b' },
@ -137,10 +132,7 @@ var RustHighlightRules = function() {
{ token: 'comment.end.block.source.rust', { token: 'comment.end.block.source.rust',
regex: '\\*/', regex: '\\*/',
next: 'pop' }, next: 'pop' },
{ defaultToken: 'comment.block.source.rust' } ] } ], { defaultToken: 'comment.block.source.rust' } ] } ] }
'#rust_escaped_character':
[ { token: 'constant.character.escape.source.rust',
regex: '\\\\(?:x[\\da-fA-F]{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)' } ] }
this.normalizeRules(); this.normalizeRules();
}; };

View file

@ -39,15 +39,92 @@ define(function(require, exports, module) {
var oop = require("../lib/oop"); var oop = require("../lib/oop");
var TextMode = require("./text").Mode; var TextMode = require("./text").Mode;
var SchemeHighlightRules = require("./scheme_highlight_rules").SchemeHighlightRules; var SchemeHighlightRules = require("./scheme_highlight_rules").SchemeHighlightRules;
var MatchingParensOutdent = require("./matching_parens_outdent").MatchingParensOutdent;
var Mode = function() { var Mode = function() {
this.HighlightRules = SchemeHighlightRules; this.HighlightRules = SchemeHighlightRules;
this.$outdent = new MatchingParensOutdent();
}; };
oop.inherits(Mode, TextMode); oop.inherits(Mode, TextMode);
(function() { (function() {
this.lineCommentStart = ";"; this.lineCommentStart = ";";
this.minorIndentFunctions = ["define", "lambda", "define-macro", "define-syntax", "syntax-rules", "define-record-type", "define-structure"];
this.$toIndent = function(str) {
return str.split('').map(function(ch) {
if (/\s/.exec(ch)) {
return ch;
} else {
return ' ';
}
}).join('');
};
this.$calculateIndent = function(line, tab) {
var baseIndent = this.$getIndent(line);
var delta = 0;
var isParen, ch;
// Walk back from end of line, find matching braces
for (var i = line.length - 1; i >= 0; i--) {
ch = line[i];
if (ch === '(') {
delta--;
isParen = true;
} else if (ch === '(' || ch === '[' || ch === '{') {
delta--;
isParen = false;
} else if (ch === ')' || ch === ']' || ch === '}') {
delta++;
}
if (delta < 0) {
break;
}
}
if (delta < 0 && isParen) {
// Were more brackets opened than closed and was a ( left open?
i += 1;
var iBefore = i;
var fn = '';
while (true) {
ch = line[i];
if (ch === ' ' || ch === '\t') {
if(this.minorIndentFunctions.indexOf(fn) !== -1) {
return this.$toIndent(line.substring(0, iBefore - 1) + tab);
} else {
return this.$toIndent(line.substring(0, i + 1));
}
} else if (ch === undefined) {
return this.$toIndent(line.substring(0, iBefore - 1) + tab);
}
fn += line[i];
i++;
}
} else if(delta < 0 && !isParen) {
// Were more brackets openend than closed and was it not a (?
return this.$toIndent(line.substring(0, i+1));
} else if(delta > 0) {
// Mere more brackets closed than opened? Outdent.
baseIndent = baseIndent.substring(0, baseIndent.length - tab.length);
return baseIndent;
} else {
// Were they nicely matched? Just indent like line before.
return baseIndent;
}
};
this.getNextLineIndent = function(state, line, tab) {
return this.$calculateIndent(line, tab);
};
this.checkOutdent = function(state, line, input) {
return this.$outdent.checkOutdent(line, input);
};
this.autoOutdent = function(state, doc, row) {
this.$outdent.autoOutdent(doc, row);
};
this.$id = "ace/mode/scheme"; this.$id = "ace/mode/scheme";
}).call(Mode.prototype); }).call(Mode.prototype);

View file

@ -38,21 +38,28 @@ var SqlHighlightRules = function() {
var keywords = ( var keywords = (
"select|insert|update|delete|from|where|and|or|group|by|order|limit|offset|having|as|case|" + "select|insert|update|delete|from|where|and|or|group|by|order|limit|offset|having|as|case|" +
"when|else|end|type|left|right|join|on|outer|desc|asc|union" "when|else|end|type|left|right|join|on|outer|desc|asc|union|create|table|primary|key|if|" +
"foreign|not|references|default|null|inner|cross|natural|database|drop|grant"
); );
var builtinConstants = ( var builtinConstants = (
"true|false|null" "true|false"
); );
var builtinFunctions = ( var builtinFunctions = (
"count|min|max|avg|sum|rank|now|coalesce" "count|min|max|avg|sum|rank|now|coalesce"
); );
var dataTypes = (
"int|numeric|decimal|date|varchar|char|bigint|float|double|bit|binary|text|set|timestamp|" +
"money|real|number|integer"
);
var keywordMapper = this.createKeywordMapper({ var keywordMapper = this.createKeywordMapper({
"support.function": builtinFunctions, "support.function": builtinFunctions,
"keyword": keywords, "keyword": keywords,
"constant.language": builtinConstants "constant.language": builtinConstants,
"storage.type": dataTypes
}, "identifier", true); }, "identifier", true);
this.$rules = { this.$rules = {

62
lib/ace/mode/sqlserver.js Normal file
View file

@ -0,0 +1,62 @@
/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2010, Ajax.org B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var TextMode = require("./text").Mode;
var SqlServerHighlightRules = require("./sqlserver_highlight_rules").SqlHighlightRules;
var Range = require("../range").Range;
var SqlServerFoldMode = require("./folding/sqlserver").FoldMode;
var Mode = function() {
this.HighlightRules = SqlServerHighlightRules;
this.foldingRules = new SqlServerFoldMode();
};
oop.inherits(Mode, TextMode);
(function() {
this.lineCommentStart = "--";
this.blockComment = {start: "/*", end: "*/"};
/**
* Override keyword completions using list created in highlight rules
*/
this.getCompletions = function(state, session, pos, prefix) {
return session.$mode.$highlightRules.completions;
};
this.$id = "ace/mode/sql";
}).call(Mode.prototype);
exports.Mode = Mode;
});

View file

@ -0,0 +1,232 @@
/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2010, Ajax.org B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules;
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var SqlServerHighlightRules = function() {
/**
* Transact-SQL Syntax Conventions: https://msdn.microsoft.com/en-us/library/ms177563.aspx
* Goal: make this imitate SSMS (SQL Server Managment Studio)
*/
// https://msdn.microsoft.com/en-us/library/ms189773.aspx
var logicalOperators = "ALL|AND|ANY|BETWEEN|EXISTS|IN|LIKE|NOT|OR|SOME";
logicalOperators += "|NULL|IS|APPLY|INNER|OUTER|LEFT|RIGHT|JOIN|CROSS"; //SSMS colors these gray too
//note: manually removed LEFT and RIGHT from built in functions below to color it same way SSMS does
var builtinFunctions = (
/* https://msdn.microsoft.com/en-us/library/ms187957.aspx */
"OPENDATASOURCE|OPENQUERY|OPENROWSET|OPENXML|" +
/* https://msdn.microsoft.com/en-us/library/ms173454.aspx */
"AVG|CHECKSUM_AGG|COUNT|COUNT_BIG|GROUPING|GROUPING_ID|MAX|MIN|STDEV|STDEVP|SUM|VAR|VARP|" +
/* https://msdn.microsoft.com/en-us/library/ms189798.aspx */
"DENSE_RANK|NTILE|RANK|ROW_NUMBER" +
/* https://msdn.microsoft.com/en-us/library/ms173823.aspx */
"@@DATEFIRST|@@DBTS|@@LANGID|@@LANGUAGE|@@LOCK_TIMEOUT|@@MAX_CONNECTIONS|@@MAX_PRECISION|@@NESTLEVEL|@@OPTIONS|@@REMSERVER|@@SERVERNAME|@@SERVICENAME|@@SPID|@@TEXTSIZE|@@VERSION|" +
/* https://msdn.microsoft.com/en-us/library/hh231076.aspx */
"CAST|CONVERT|PARSE|TRY_CAST|TRY_CONVERT|TRY_PARSE" +
/* https://msdn.microsoft.com/en-us/library/ms186285.aspx */
"@@CURSOR_ROWS|@@FETCH_STATUS|CURSOR_STATUS|" +
/* https://msdn.microsoft.com/en-us/library/ms186724.aspx */
"@@DATEFIRST|@@LANGUAGE|CURRENT_TIMESTAMP|DATEADD|DATEDIFF|DATEFROMPARTS|DATENAME|DATEPART|DATETIME2FROMPARTS|DATETIMEFROMPARTS|DATETIMEOFFSETFROMPARTS|DAY|EOMONTH|GETDATE|GETUTCDATE|ISDATE|MONTH|SET DATEFIRST|SET DATEFORMAT|SET LANGUAGE|SMALLDATETIMEFROMPARTS|SP_HELPLANGUAGE|SWITCHOFFSET|SYSDATETIME|SYSDATETIMEOFFSET|SYSUTCDATETIME|TIMEFROMPARTS|TODATETIMEOFFSET|YEAR|" +
/* https://msdn.microsoft.com/en-us/library/hh213226.aspx */
"CHOOSE|IIF|" +
/* https://msdn.microsoft.com/en-us/library/ms177516.aspx */
"ABS|ACOS|ASIN|ATAN|ATN2|CEILING|COS|COT|DEGREES|EXP|FLOOR|LOG|LOG10|PI|POWER|RADIANS|RAND|ROUND|SIGN|SIN|SQRT|SQUARE|TAN|" +
/* https://msdn.microsoft.com/en-us/library/ms187812.aspx */
"@@PROCID|APPLOCK_MODE|APPLOCK_TEST|APP_NAME|ASSEMBLYPROPERTY|COLUMNPROPERTY|COL_LENGTH|COL_NAME|DATABASEPROPERTYEX|DATABASE_PRINCIPAL_ID|DB_ID|DB_NAME|FILEGROUPPROPERTY|FILEGROUP_ID|FILEGROUP_NAME|FILEPROPERTY|FILE_ID|FILE_IDEX|FILE_NAME|FULLTEXTCATALOGPROPERTY|FULLTEXTSERVICEPROPERTY|INDEXKEY_PROPERTY|INDEXPROPERTY|INDEX_COL|OBJECTPROPERTY|OBJECTPROPERTYEX|OBJECT_DEFINITION|OBJECT_ID|OBJECT_NAME|OBJECT_SCHEMA_NAME|ORIGINAL_DB_NAME|PARSENAME|SCHEMA_ID|SCHEMA_NAME|SCOPE_IDENTITY|SERVERPROPERTY|STATS_DATE|TYPEPROPERTY|TYPE_ID|TYPE_NAME|" +
/* https://msdn.microsoft.com/en-us/library/ms186236.aspx */
"CERTENCODED|CERTPRIVATEKEY|CURRENT_USER|DATABASE_PRINCIPAL_ID|HAS_PERMS_BY_NAME|IS_MEMBER|IS_ROLEMEMBER|IS_SRVROLEMEMBER|ORIGINAL_LOGIN|PERMISSIONS|PWDCOMPARE|PWDENCRYPT|SCHEMA_ID|SCHEMA_NAME|SESSION_USER|SUSER_ID|SUSER_NAME|SUSER_SID|SUSER_SNAME|SYS.FN_BUILTIN_PERMISSIONS|SYS.FN_GET_AUDIT_FILE|SYS.FN_MY_PERMISSIONS|SYSTEM_USER|USER_ID|USER_NAME|" +
/* https://msdn.microsoft.com/en-us/library/ms181984.aspx */
"ASCII|CHAR|CHARINDEX|CONCAT|DIFFERENCE|FORMAT|LEN|LOWER|LTRIM|NCHAR|PATINDEX|QUOTENAME|REPLACE|REPLICATE|REVERSE|RTRIM|SOUNDEX|SPACE|STR|STUFF|SUBSTRING|UNICODE|UPPER|" +
/* https://msdn.microsoft.com/en-us/library/ms187786.aspx */
"$PARTITION|@@ERROR|@@IDENTITY|@@PACK_RECEIVED|@@ROWCOUNT|@@TRANCOUNT|BINARY_CHECKSUM|CHECKSUM|CONNECTIONPROPERTY|CONTEXT_INFO|CURRENT_REQUEST_ID|ERROR_LINE|ERROR_MESSAGE|ERROR_NUMBER|ERROR_PROCEDURE|ERROR_SEVERITY|ERROR_STATE|FORMATMESSAGE|GETANSINULL|GET_FILESTREAM_TRANSACTION_CONTEXT|HOST_ID|HOST_NAME|ISNULL|ISNUMERIC|MIN_ACTIVE_ROWVERSION|NEWID|NEWSEQUENTIALID|ROWCOUNT_BIG|XACT_STATE|" +
/* https://msdn.microsoft.com/en-us/library/ms177520.aspx */
"@@CONNECTIONS|@@CPU_BUSY|@@IDLE|@@IO_BUSY|@@PACKET_ERRORS|@@PACK_RECEIVED|@@PACK_SENT|@@TIMETICKS|@@TOTAL_ERRORS|@@TOTAL_READ|@@TOTAL_WRITE|FN_VIRTUALFILESTATS|" +
/* https://msdn.microsoft.com/en-us/library/ms188353.aspx */
"PATINDEX|TEXTPTR|TEXTVALID|" +
/* other */
"COALESCE|NULLIF"
);
// https://msdn.microsoft.com/en-us/library/ms187752.aspx
var dataTypes = ("BIGINT|BINARY|BIT|CHAR|CURSOR|DATE|DATETIME|DATETIME2|DATETIMEOFFSET|DECIMAL|FLOAT|HIERARCHYID|IMAGE|INTEGER|INT|MONEY|NCHAR|NTEXT|NUMERIC|NVARCHAR|REAL|SMALLDATETIME|SMALLINT|SMALLMONEY|SQL_VARIANT|TABLE|TEXT|TIME|TIMESTAMP|TINYINT|UNIQUEIDENTIFIER|VARBINARY|VARCHAR|XML");
//https://msdn.microsoft.com/en-us/library/ms176007.aspx (these are lower case!)
var builtInStoredProcedures = "sp_addextendedproc|sp_addextendedproperty|sp_addmessage|sp_addtype|sp_addumpdevice|sp_add_data_file_recover_suspect_db|sp_add_log_file_recover_suspect_db|sp_altermessage|sp_attach_db|sp_attach_single_file_db|sp_autostats|sp_bindefault|sp_bindrule|sp_bindsession|sp_certify_removable|sp_clean_db_file_free_space|sp_clean_db_free_space|sp_configure|sp_control_plan_guide|sp_createstats|sp_create_plan_guide|sp_create_plan_guide_from_handle|sp_create_removable|sp_cycle_errorlog|sp_datatype_info|sp_dbcmptlevel|sp_dbmmonitoraddmonitoring|sp_dbmmonitorchangealert|sp_dbmmonitorchangemonitoring|sp_dbmmonitordropalert|sp_dbmmonitordropmonitoring|sp_dbmmonitorhelpalert|sp_dbmmonitorhelpmonitoring|sp_dbmmonitorresults|sp_db_increased_partitions|sp_delete_backuphistory|sp_depends|sp_describe_first_result_set|sp_describe_undeclared_parameters|sp_detach_db|sp_dropdevice|sp_dropextendedproc|sp_dropextendedproperty|sp_dropmessage|sp_droptype|sp_execute|sp_executesql|sp_getapplock|sp_getbindtoken|sp_help|sp_helpconstraint|sp_helpdb|sp_helpdevice|sp_helpextendedproc|sp_helpfile|sp_helpfilegroup|sp_helpindex|sp_helplanguage|sp_helpserver|sp_helpsort|sp_helpstats|sp_helptext|sp_helptrigger|sp_indexoption|sp_invalidate_textptr|sp_lock|sp_monitor|sp_prepare|sp_prepexec|sp_prepexecrpc|sp_procoption|sp_recompile|sp_refreshview|sp_releaseapplock|sp_rename|sp_renamedb|sp_resetstatus|sp_sequence_get_range|sp_serveroption|sp_setnetname|sp_settriggerorder|sp_spaceused|sp_tableoption|sp_unbindefault|sp_unbindrule|sp_unprepare|sp_updateextendedproperty|sp_updatestats|sp_validname|sp_who|sys.sp_merge_xtp_checkpoint_files|sys.sp_xtp_bind_db_resource_pool|sys.sp_xtp_checkpoint_force_garbage_collection|sys.sp_xtp_control_proc_exec_stats|sys.sp_xtp_control_query_exec_stats|sys.sp_xtp_unbind_db_resource_pool";
// https://msdn.microsoft.com/en-us/library/ms189822.aspx
var keywords = "ABSOLUTE|ACTION|ADA|ADD|ADMIN|AFTER|AGGREGATE|ALIAS|ALL|ALLOCATE|ALTER|AND|ANY|ARE|ARRAY|AS|ASC|ASENSITIVE|ASSERTION|ASYMMETRIC|AT|ATOMIC|AUTHORIZATION|BACKUP|BEFORE|BEGIN|BETWEEN|BIT_LENGTH|BLOB|BOOLEAN|BOTH|BREADTH|BREAK|BROWSE|BULK|BY|CALL|CALLED|CARDINALITY|CASCADE|CASCADED|CASE|CATALOG|CHARACTER|CHARACTER_LENGTH|CHAR_LENGTH|CHECK|CHECKPOINT|CLASS|CLOB|CLOSE|CLUSTERED|COALESCE|COLLATE|COLLATION|COLLECT|COLUMN|COMMIT|COMPLETION|COMPUTE|CONDITION|CONNECT|CONNECTION|CONSTRAINT|CONSTRAINTS|CONSTRUCTOR|CONTAINS|CONTAINSTABLE|CONTINUE|CORR|CORRESPONDING|COVAR_POP|COVAR_SAMP|CREATE|CROSS|CUBE|CUME_DIST|CURRENT|CURRENT_CATALOG|CURRENT_DATE|CURRENT_DEFAULT_TRANSFORM_GROUP|CURRENT_PATH|CURRENT_ROLE|CURRENT_SCHEMA|CURRENT_TIME|CURRENT_TRANSFORM_GROUP_FOR_TYPE|CYCLE|DATA|DATABASE|DBCC|DEALLOCATE|DEC|DECLARE|DEFAULT|DEFERRABLE|DEFERRED|DELETE|DENY|DEPTH|DEREF|DESC|DESCRIBE|DESCRIPTOR|DESTROY|DESTRUCTOR|DETERMINISTIC|DIAGNOSTICS|DICTIONARY|DISCONNECT|DISK|DISTINCT|DISTRIBUTED|DOMAIN|DOUBLE|DROP|DUMP|DYNAMIC|EACH|ELEMENT|ELSE|END|END-EXEC|EQUALS|ERRLVL|ESCAPE|EVERY|EXCEPT|EXCEPTION|EXEC|EXECUTE|EXISTS|EXIT|EXTERNAL|EXTRACT|FETCH|FILE|FILLFACTOR|FILTER|FIRST|FOR|FOREIGN|FORTRAN|FOUND|FREE|FREETEXT|FREETEXTTABLE|FROM|FULL|FULLTEXTTABLE|FUNCTION|FUSION|GENERAL|GET|GLOBAL|GO|GOTO|GRANT|GROUP|HAVING|HOLD|HOLDLOCK|HOST|HOUR|IDENTITY|IDENTITYCOL|IDENTITY_INSERT|IF|IGNORE|IMMEDIATE|IN|INCLUDE|INDEX|INDICATOR|INITIALIZE|INITIALLY|INNER|INOUT|INPUT|INSENSITIVE|INSERT|INTEGER|INTERSECT|INTERSECTION|INTERVAL|INTO|IS|ISOLATION|ITERATE|JOIN|KEY|KILL|LANGUAGE|LARGE|LAST|LATERAL|LEADING|LESS|LEVEL|LIKE|LIKE_REGEX|LIMIT|LINENO|LN|LOAD|LOCAL|LOCALTIME|LOCALTIMESTAMP|LOCATOR|MAP|MATCH|MEMBER|MERGE|METHOD|MINUTE|MOD|MODIFIES|MODIFY|MODULE|MULTISET|NAMES|NATIONAL|NATURAL|NCLOB|NEW|NEXT|NO|NOCHECK|NONCLUSTERED|NONE|NORMALIZE|NOT|NULL|NULLIF|OBJECT|OCCURRENCES_REGEX|OCTET_LENGTH|OF|OFF|OFFSETS|OLD|ON|ONLY|OPEN|OPERATION|OPTION|OR|ORDER|ORDINALITY|OUT|OUTER|OUTPUT|OVER|OVERLAPS|OVERLAY|PAD|PARAMETER|PARAMETERS|PARTIAL|PARTITION|PASCAL|PATH|PERCENT|PERCENTILE_CONT|PERCENTILE_DISC|PERCENT_RANK|PIVOT|PLAN|POSITION|POSITION_REGEX|POSTFIX|PRECISION|PREFIX|PREORDER|PREPARE|PRESERVE|PRIMARY|PRINT|PRIOR|PRIVILEGES|PROC|PROCEDURE|PUBLIC|RAISERROR|RANGE|READ|READS|READTEXT|RECONFIGURE|RECURSIVE|REF|REFERENCES|REFERENCING|REGR_AVGX|REGR_AVGY|REGR_COUNT|REGR_INTERCEPT|REGR_R2|REGR_SLOPE|REGR_SXX|REGR_SXY|REGR_SYY|RELATIVE|RELEASE|REPLICATION|RESTORE|RESTRICT|RESULT|RETURN|RETURNS|REVERT|REVOKE|ROLE|ROLLBACK|ROLLUP|ROUTINE|ROW|ROWCOUNT|ROWGUIDCOL|ROWS|RULE|SAVE|SAVEPOINT|SCHEMA|SCOPE|SCROLL|SEARCH|SECOND|SECTION|SECURITYAUDIT|SELECT|SEMANTICKEYPHRASETABLE|SEMANTICSIMILARITYDETAILSTABLE|SEMANTICSIMILARITYTABLE|SENSITIVE|SEQUENCE|SESSION|SET|SETS|SETUSER|SHUTDOWN|SIMILAR|SIZE|SOME|SPECIFIC|SPECIFICTYPE|SQL|SQLCA|SQLCODE|SQLERROR|SQLEXCEPTION|SQLSTATE|SQLWARNING|START|STATE|STATEMENT|STATIC|STATISTICS|STDDEV_POP|STDDEV_SAMP|STRUCTURE|SUBMULTISET|SUBSTRING_REGEX|SYMMETRIC|SYSTEM|TABLESAMPLE|TEMPORARY|TERMINATE|TEXTSIZE|THAN|THEN|TIMEZONE_HOUR|TIMEZONE_MINUTE|TO|TOP|TRAILING|TRAN|TRANSACTION|TRANSLATE|TRANSLATE_REGEX|TRANSLATION|TREAT|TRIGGER|TRIM|TRUNCATE|TSEQUAL|UESCAPE|UNDER|UNION|UNIQUE|UNKNOWN|UNNEST|UNPIVOT|UPDATE|UPDATETEXT|USAGE|USE|USER|USING|VALUE|VALUES|VARIABLE|VARYING|VAR_POP|VAR_SAMP|VIEW|WAITFOR|WHEN|WHENEVER|WHERE|WHILE|WIDTH_BUCKET|WINDOW|WITH|WITHIN|WITHIN GROUP|WITHOUT|WORK|WRITE|WRITETEXT|XMLAGG|XMLATTRIBUTES|XMLBINARY|XMLCAST|XMLCOMMENT|XMLCONCAT|XMLDOCUMENT|XMLELEMENT|XMLEXISTS|XMLFOREST|XMLITERATE|XMLNAMESPACES|XMLPARSE|XMLPI|XMLQUERY|XMLSERIALIZE|XMLTABLE|XMLTEXT|XMLVALIDATE|ZONE";
// Microsoft's keyword list is missing a lot of things that are located on various other pages
// https://msdn.microsoft.com/en-us/library/ms187373.aspx, https://msdn.microsoft.com/en-us/library/ms181714.aspx
keywords += "|KEEPIDENTITY|KEEPDEFAULTS|IGNORE_CONSTRAINTS|IGNORE_TRIGGERS|XLOCK|FORCESCAN|FORCESEEK|HOLDLOCK|NOLOCK|NOWAIT|PAGLOCK|READCOMMITTED|READCOMMITTEDLOCK|READPAST|READUNCOMMITTED|REPEATABLEREAD|ROWLOCK|SERIALIZABLE|SNAPSHOT|SPATIAL_WINDOW_MAX_CELLS|TABLOCK|TABLOCKX|UPDLOCK|XLOCK|IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX|EXPAND|VIEWS|FAST|FORCE|KEEP|KEEPFIXED|MAXDOP|MAXRECURSION|OPTIMIZE|PARAMETERIZATION|SIMPLE|FORCED|RECOMPILE|ROBUST|PLAN|SPATIAL_WINDOW_MAX_CELLS|NOEXPAND|HINT";
// https://msdn.microsoft.com/en-us/library/ms173815.aspx
keywords += "|LOOP|HASH|MERGE|REMOTE";
// https://msdn.microsoft.com/en-us/library/ms175976.aspx
keywords += "|TRY|CATCH|THROW";
// highlighted words in SSMS that I'm not even sure where they come from
keywords += "|TYPE";
//remove specific built in types from keyword list
keywords = keywords.split('|');
keywords = keywords.filter(function(value, index, self) {
return logicalOperators.split('|').indexOf(value) === -1 && builtinFunctions.split('|').indexOf(value) === -1 && dataTypes.split('|').indexOf(value) === -1;
});
keywords = keywords.sort().join('|');
var keywordMapper = this.createKeywordMapper({
"constant.language": logicalOperators,
"storage.type": dataTypes,
"support.function": builtinFunctions,
"support.storedprocedure": builtInStoredProcedures,
"keyword": keywords,
}, "identifier", true);
//https://msdn.microsoft.com/en-us/library/ms190356.aspx
var setStatements = "SET ANSI_DEFAULTS|SET ANSI_NULLS|SET ANSI_NULL_DFLT_OFF|SET ANSI_NULL_DFLT_ON|SET ANSI_PADDING|SET ANSI_WARNINGS|SET ARITHABORT|SET ARITHIGNORE|SET CONCAT_NULL_YIELDS_NULL|SET CURSOR_CLOSE_ON_COMMIT|SET DATEFIRST|SET DATEFORMAT|SET DEADLOCK_PRIORITY|SET FIPS_FLAGGER|SET FMTONLY|SET FORCEPLAN|SET IDENTITY_INSERT|SET IMPLICIT_TRANSACTIONS|SET LANGUAGE|SET LOCK_TIMEOUT|SET NOCOUNT|SET NOEXEC|SET NUMERIC_ROUNDABORT|SET OFFSETS|SET PARSEONLY|SET QUERY_GOVERNOR_COST_LIMIT|SET QUOTED_IDENTIFIER|SET REMOTE_PROC_TRANSACTIONS|SET ROWCOUNT|SET SHOWPLAN_ALL|SET SHOWPLAN_TEXT|SET SHOWPLAN_XML|SET STATISTICS IO|SET STATISTICS PROFILE|SET STATISTICS TIME|SET STATISTICS XML|SET TEXTSIZE|SET XACT_ABORT".split('|');
var isolationLevels = "READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SNAPSHOP|SERIALIZABLE".split('|');
for (var i = 0; i < isolationLevels.length; i++) {
setStatements.push('SET TRANSACTION ISOLATION LEVEL ' + isolationLevels[i]);
}
this.$rules = {
start: [{
token: "string.start",
regex: "'",
next: [{
token: "constant.language.escape",
regex: /''/
}, {
token: "string.end",
next: "start",
regex: "'"
}, {
defaultToken: "string"
}]
},
DocCommentHighlightRules.getStartRule("doc-start"), {
token: "comment",
regex: "--.*$"
}, {
token: "comment",
start: "/\\*",
end: "\\*/"
}, {
token: "constant.numeric", // float
regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token: keywordMapper,
regex: "@{0,2}[a-zA-Z_$][a-zA-Z0-9_$]*\\b(?!])" //up to 2 @symbols for some built in functions
}, {
token: "constant.class",
regex: "@@?[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
//https://msdn.microsoft.com/en-us/library/ms174986.aspx
token: "keyword.operator",
regex: "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=|\\*"
}, {
token: "paren.lparen",
regex: "[\\(]"
}, {
token: "paren.rparen",
regex: "[\\)]"
}, {
token: "punctuation",
regex: ",|;"
}, {
token: "text",
regex: "\\s+"
}],
comment: [
DocCommentHighlightRules.getTagRule(), {
token: "comment",
regex: "\\*\\/",
next: "no_regex"
}, {
defaultToken: "comment",
caseInsensitive: true
}],
};
//add each set statment as regex at top of rules so that they are processed first because they require multiple words
//note: this makes the statements not match if they are not upper case.. which is not ideal but I don't know of an easy way to fix this
for (var i = 0; i < setStatements.length; i++) {
this.$rules.start.unshift({
token: "set.statement",
regex: setStatements[i]
});
}
this.embedRules(DocCommentHighlightRules, "doc-", [DocCommentHighlightRules.getEndRule("start")]);
this.normalizeRules();
//prepare custom keyword completions used by mode to override default completor
//this allows for custom 'meta' and proper case of completions
var completions = [];
var addCompletions = function(arr, meta) {
arr.forEach(function(v) {
completions.push({
name: v,
value: v,
score: 0,
meta: meta,
});
});
};
addCompletions(builtInStoredProcedures.split('|'), 'procedure');
addCompletions(logicalOperators.split('|'), 'operator');
addCompletions(builtinFunctions.split('|'), 'function');
addCompletions(dataTypes.split('|'), 'type');
addCompletions(setStatements, 'statement');
addCompletions(keywords.split('|'), 'keyword');
this.completions = completions;
};
oop.inherits(SqlServerHighlightRules, TextHighlightRules);
exports.SqlHighlightRules = SqlServerHighlightRules;
});

View file

@ -57,6 +57,10 @@ var TomlHighlightRules = function() {
regex : '"(?=.)', regex : '"(?=.)',
next : "qqstring" next : "qqstring"
}, },
{
token: ["variable.keygroup.toml"],
regex: "(?:^\\s*)(\\[\\[([^\\]]+)\\]\\])"
},
{ {
token: ["variable.keygroup.toml"], token: ["variable.keygroup.toml"],
regex: "(?:^\\s*)(\\[([^\\]]+)\\])" regex: "(?:^\\s*)(\\[([^\\]]+)\\])"
@ -100,4 +104,4 @@ var TomlHighlightRules = function() {
oop.inherits(TomlHighlightRules, TextHighlightRules); oop.inherits(TomlHighlightRules, TextHighlightRules);
exports.TomlHighlightRules = TomlHighlightRules; exports.TomlHighlightRules = TomlHighlightRules;
}); });

View file

@ -3,7 +3,7 @@
* *
* Copyright (c) 2012, Ajax.org B.V. * Copyright (c) 2012, Ajax.org B.V.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
@ -14,7 +14,7 @@
* * Neither the name of Ajax.org B.V. nor the * * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products * names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission. * derived from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@ -85,29 +85,35 @@ var VBScriptHighlightRules = function() {
{ {
token: "punctuation.definition.comment.asp", token: "punctuation.definition.comment.asp",
regex: "'|REM", regex: "'|REM",
next: "comment" next: "comment",
caseInsensitive: true
}, },
{ {
token: [ token: [
"keyword.control.asp" "keyword.control.asp"
], ],
regex: "\\b(?:If|Then|Else|ElseIf|Else If|End If|While|Wend|For|To|Each|Case|Select|End Select|Return|Continue|Do|Until|Loop|Next|With|Exit Do|Exit For|Exit Function|Exit Property|Exit Sub|IIf)\\b" regex: "\\b(?:If|Then|Else|ElseIf|Else If|End If|While|Wend|For|To|Each|Case|Select|End Select|Return|Continue|Do|Until|Loop|Next|With|Exit Do|Exit For|Exit Function|Exit Property|Exit Sub|IIf)\\b",
caseInsensitive: true
}, },
{ {
token: "keyword.operator.asp", token: "keyword.operator.asp",
regex: "\\b(?:Mod|And|Not|Or|Xor|as)\\b" regex: "\\b(?:Mod|And|Not|Or|Xor|as)\\b",
caseInsensitive: true
}, },
{ {
token: "storage.type.asp", token: "storage.type.asp",
regex: "Dim|Call|Class|Const|Dim|Redim|Function|Sub|Private Sub|Public Sub|End sub|End Function|Set|Let|Get|New|Randomize|Option Explicit|On Error Resume Next|On Error GoTo" regex: "Dim|Call|Class|Const|Dim|Redim|Function|Sub|Private Sub|Public Sub|End sub|End Function|Set|Let|Get|New|Randomize|Option Explicit|On Error Resume Next|On Error GoTo",
caseInsensitive: true
}, },
{ {
token: "storage.modifier.asp", token: "storage.modifier.asp",
regex: "\\b(?:Private|Public|Default)\\b" regex: "\\b(?:Private|Public|Default)\\b",
caseInsensitive: true
}, },
{ {
token: "constant.language.asp", token: "constant.language.asp",
regex: "\\b(?:Empty|False|Nothing|Null|True)\\b" regex: "\\b(?:Empty|False|Nothing|Null|True)\\b",
caseInsensitive: true
}, },
{ {
token: "punctuation.definition.string.begin.asp", token: "punctuation.definition.string.begin.asp",
@ -122,23 +128,28 @@ var VBScriptHighlightRules = function() {
}, },
{ {
token: "support.class.asp", token: "support.class.asp",
regex: "\\b(?:Application|ObjectContext|Request|Response|Server|Session)\\b" regex: "\\b(?:Application|ObjectContext|Request|Response|Server|Session)\\b",
caseInsensitive: true
}, },
{ {
token: "support.class.collection.asp", token: "support.class.collection.asp",
regex: "\\b(?:Contents|StaticObjects|ClientCertificate|Cookies|Form|QueryString|ServerVariables)\\b" regex: "\\b(?:Contents|StaticObjects|ClientCertificate|Cookies|Form|QueryString|ServerVariables)\\b",
caseInsensitive: true
}, },
{ {
token: "support.constant.asp", token: "support.constant.asp",
regex: "\\b(?:TotalBytes|Buffer|CacheControl|Charset|ContentType|Expires|ExpiresAbsolute|IsClientConnected|PICS|Status|ScriptTimeout|CodePage|LCID|SessionID|Timeout)\\b" regex: "\\b(?:TotalBytes|Buffer|CacheControl|Charset|ContentType|Expires|ExpiresAbsolute|IsClientConnected|PICS|Status|ScriptTimeout|CodePage|LCID|SessionID|Timeout)\\b",
caseInsensitive: true
}, },
{ {
token: "support.function.asp", token: "support.function.asp",
regex: "\\b(?:Lock|Unlock|SetAbort|SetComplete|BinaryRead|AddHeader|AppendToLog|BinaryWrite|Clear|End|Flush|Redirect|Write|CreateObject|HTMLEncode|MapPath|URLEncode|Abandon|Convert|Regex)\\b" regex: "\\b(?:Lock|Unlock|SetAbort|SetComplete|BinaryRead|AddHeader|AppendToLog|BinaryWrite|Clear|End|Flush|Redirect|Write|CreateObject|HTMLEncode|MapPath|URLEncode|Abandon|Convert|Regex)\\b",
caseInsensitive: true
}, },
{ {
token: "support.function.event.asp", token: "support.function.event.asp",
regex: "\\b(?:Application_OnEnd|Application_OnStart|OnTransactionAbort|OnTransactionCommit|Session_OnEnd|Session_OnStart)\\b" regex: "\\b(?:Application_OnEnd|Application_OnStart|OnTransactionAbort|OnTransactionCommit|Session_OnEnd|Session_OnStart)\\b",
caseInsensitive: true
}, },
// { // {
// token: [ // token: [
@ -148,7 +159,8 @@ var VBScriptHighlightRules = function() {
// }, // },
{ {
token: "support.function.vb.asp", token: "support.function.vb.asp",
regex: "\\b(?:Array|Add|Asc|Atn|CBool|CByte|CCur|CDate|CDbl|Chr|CInt|CLng|Conversions|Cos|CreateObject|CSng|CStr|Date|DateAdd|DateDiff|DatePart|DateSerial|DateValue|Day|Derived|Math|Escape|Eval|Exists|Exp|Filter|FormatCurrency|FormatDateTime|FormatNumber|FormatPercent|GetLocale|GetObject|GetRef|Hex|Hour|InputBox|InStr|InStrRev|Int|Fix|IsArray|IsDate|IsEmpty|IsNull|IsNumeric|IsObject|Item|Items|Join|Keys|LBound|LCase|Left|Len|LoadPicture|Log|LTrim|RTrim|Trim|Maths|Mid|Minute|Month|MonthName|MsgBox|Now|Oct|Remove|RemoveAll|Replace|RGB|Right|Rnd|Round|ScriptEngine|ScriptEngineBuildVersion|ScriptEngineMajorVersion|ScriptEngineMinorVersion|Second|SetLocale|Sgn|Sin|Space|Split|Sqr|StrComp|String|StrReverse|Tan|Time|Timer|TimeSerial|TimeValue|TypeName|UBound|UCase|Unescape|VarType|Weekday|WeekdayName|Year)\\b" regex: "\\b(?:Array|Add|Asc|Atn|CBool|CByte|CCur|CDate|CDbl|Chr|CInt|CLng|Conversions|Cos|CreateObject|CSng|CStr|Date|DateAdd|DateDiff|DatePart|DateSerial|DateValue|Day|Derived|Math|Escape|Eval|Exists|Exp|Filter|FormatCurrency|FormatDateTime|FormatNumber|FormatPercent|GetLocale|GetObject|GetRef|Hex|Hour|InputBox|InStr|InStrRev|Int|Fix|IsArray|IsDate|IsEmpty|IsNull|IsNumeric|IsObject|Item|Items|Join|Keys|LBound|LCase|Left|Len|LoadPicture|Log|LTrim|RTrim|Trim|Maths|Mid|Minute|Month|MonthName|MsgBox|Now|Oct|Remove|RemoveAll|Replace|RGB|Right|Rnd|Round|ScriptEngine|ScriptEngineBuildVersion|ScriptEngineMajorVersion|ScriptEngineMinorVersion|Second|SetLocale|Sgn|Sin|Space|Split|Sqr|StrComp|String|StrReverse|Tan|Time|Timer|TimeSerial|TimeValue|TypeName|UBound|UCase|Unescape|VarType|Weekday|WeekdayName|Year)\\b",
caseInsensitive: true
}, },
{ {
token: [ token: [
@ -158,7 +170,8 @@ var VBScriptHighlightRules = function() {
}, },
{ {
token: "support.type.vb.asp", token: "support.type.vb.asp",
regex: "\\b(?:vbtrue|vbfalse|vbcr|vbcrlf|vbformfeed|vblf|vbnewline|vbnullchar|vbnullstring|int32|vbtab|vbverticaltab|vbbinarycompare|vbtextcomparevbsunday|vbmonday|vbtuesday|vbwednesday|vbthursday|vbfriday|vbsaturday|vbusesystemdayofweek|vbfirstjan1|vbfirstfourdays|vbfirstfullweek|vbgeneraldate|vblongdate|vbshortdate|vblongtime|vbshorttime|vbobjecterror|vbEmpty|vbNull|vbInteger|vbLong|vbSingle|vbDouble|vbCurrency|vbDate|vbString|vbObject|vbError|vbBoolean|vbVariant|vbDataObject|vbDecimal|vbByte|vbArray)\\b" regex: "\\b(?:vbtrue|vbfalse|vbcr|vbcrlf|vbformfeed|vblf|vbnewline|vbnullchar|vbnullstring|int32|vbtab|vbverticaltab|vbbinarycompare|vbtextcomparevbsunday|vbmonday|vbtuesday|vbwednesday|vbthursday|vbfriday|vbsaturday|vbusesystemdayofweek|vbfirstjan1|vbfirstfourdays|vbfirstfullweek|vbgeneraldate|vblongdate|vbshortdate|vblongtime|vbshorttime|vbobjecterror|vbEmpty|vbNull|vbInteger|vbLong|vbSingle|vbDouble|vbCurrency|vbDate|vbString|vbObject|vbError|vbBoolean|vbVariant|vbDataObject|vbDecimal|vbByte|vbArray)\\b",
caseInsensitive: true
}, },
{ {
token: [ token: [

View file

@ -53,7 +53,7 @@ oop.inherits(Mode, TextMode);
this.blockComment = {start: "<!--", end: "-->"}; this.blockComment = {start: "<!--", end: "-->"};
this.createWorker = function(session) { this.createWorker = function(session) {
var worker = new WorkerClient(["ace"], "ace/mode/xml_worker", "Worker"); var worker = new WorkerClient(["ace"], "ace/mode/xml_worker", "Worker");
worker.attachToDocument(session.getDocument()); worker.attachToDocument(session.getDocument());

View file

@ -35,8 +35,10 @@ var oop = require("../lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var XmlHighlightRules = function(normalize) { var XmlHighlightRules = function(normalize) {
// http://www.w3.org/TR/REC-xml/#NT-NameChar
var tagRegex = "[a-zA-Z][-_a-zA-Z0-9]*"; // NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
// NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
var tagRegex = "[_:a-zA-Z\xc0-\uffff][-_:.a-zA-Z0-9\xc0-\uffff]*";
this.$rules = { this.$rules = {
start : [ start : [

View file

@ -83,15 +83,15 @@ function onMouseDown(e) {
var selectionMode; var selectionMode;
if (editor.$mouseHandler.$enableJumpToDef) { if (editor.$mouseHandler.$enableJumpToDef) {
if (ctrl && alt || accel && alt) if (ctrl && alt || accel && alt)
selectionMode = "add"; selectionMode = shift ? "block" : "add";
else if (alt) else if (alt && editor.$blockSelectEnabled)
selectionMode = "block"; selectionMode = "block";
} else { } else {
if (accel && !alt) { if (accel && !alt) {
selectionMode = "add"; selectionMode = "add";
if (!isMultiSelect && shift) if (!isMultiSelect && shift)
return; return;
} else if (alt) { } else if (alt && editor.$blockSelectEnabled) {
selectionMode = "block"; selectionMode = "block";
} }
} }
@ -117,7 +117,7 @@ function onMouseDown(e) {
if (shift) { if (shift) {
oldRange = null; oldRange = null;
range = selection.ranges[0]; range = selection.ranges[0] || range;
editor.removeSelectionMarker(range); editor.removeSelectionMarker(range);
} }
editor.once("mouseup", function() { editor.once("mouseup", function() {

View file

@ -754,9 +754,9 @@ var Editor = require("./editor").Editor;
if (fr < 0) fr = 0; if (fr < 0) fr = 0;
if (lr >= max) lr = max - 1; if (lr >= max) lr = max - 1;
} }
var lines = this.session.doc.removeLines(fr, lr); var lines = this.session.removeFullLines(fr, lr);
lines = this.$reAlignText(lines, guessRange); lines = this.$reAlignText(lines, guessRange);
this.session.doc.insert({row: fr, column: 0}, lines.join("\n") + "\n"); this.session.insert({row: fr, column: 0}, lines.join("\n") + "\n");
if (!guessRange) { if (!guessRange) {
range.start.column = 0; range.start.column = 0;
range.end.column = lines[lines.length - 1].length; range.end.column = lines[lines.length - 1].length;
@ -924,7 +924,8 @@ function addAltCursorListeners(editor){
var el = editor.textInput.getElement(); var el = editor.textInput.getElement();
var altCursor = false; var altCursor = false;
event.addListener(el, "keydown", function(e) { event.addListener(el, "keydown", function(e) {
if (e.keyCode == 18 && !(e.ctrlKey || e.shiftKey || e.metaKey)) { var altDown = e.keyCode == 18 && !(e.ctrlKey || e.shiftKey || e.metaKey);
if (editor.$blockSelectEnabled && altDown) {
if (!altCursor) { if (!altCursor) {
editor.renderer.setMouseCursor("crosshair"); editor.renderer.setMouseCursor("crosshair");
altCursor = true; altCursor = true;
@ -962,6 +963,12 @@ require("./config").defineOptions(Editor.prototype, "editor", {
} }
}, },
value: true value: true
},
enableBlockSelect: {
set: function(val) {
this.$blockSelectEnabled = val;
},
value: true
} }
}); });

View file

@ -30,6 +30,7 @@
if (typeof process !== "undefined") { if (typeof process !== "undefined") {
require("amd-loader"); require("amd-loader");
require("./test/mockdom");
} }
define(function(require, exports, module) { define(function(require, exports, module) {
@ -41,6 +42,7 @@ var Range = require("./range").Range;
var Editor = require("./editor").Editor; var Editor = require("./editor").Editor;
var EditSession = require("./edit_session").EditSession; var EditSession = require("./edit_session").EditSession;
var MockRenderer = require("./test/mockrenderer").MockRenderer; var MockRenderer = require("./test/mockrenderer").MockRenderer;
var UndoManager = require("./undomanager").UndoManager;
var editor; var editor;
var exec = function(name, times, args) { var exec = function(name, times, args) {
@ -82,11 +84,11 @@ function setSelection(editor, data) {
return isBackwards ? { return isBackwards ? {
start: end, start: end,
end: start, end: start,
isBackwards: true isBackwards: isBackwards
} : { } : {
start: start, start: start,
end: end, end: end,
isBackwards: true isBackwards: isBackwards
}; };
})); }));
} }
@ -223,19 +225,19 @@ module.exports = {
assert.equal(editor.getValue(),"l1\nl1\nl2\nl2\nl3\nl3\nl4\nl4"); assert.equal(editor.getValue(),"l1\nl1\nl2\nl2\nl3\nl3\nl4\nl4");
testSelection(editor, [[1,0],[3,0],[5,0],[7,0]]); testSelection(editor, [[1,0],[3,0],[5,0],[7,0]]);
setSelection(editor, [[1,2],[1,0,1,1],[3,0,3,1],[5,0,5,1],[7,0,7,1]]); setSelection(editor, [[1,2],[1,1,1,0],[3,0,3,1],[5,0,5,1],[7,0,7,1]]);
exec("copylinesdown"); exec("copylinesdown");
exec("copylinesup"); exec("copylinesup");
assert.equal(editor.getValue(),"l1\nl1\nl1\nl1\nl2\nl2\nl2\nl2\nl3\nl3\nl3\nl3\nl4\nl4\nl4\nl4"); assert.equal(editor.getValue(),"l1\nl1\nl1\nl1\nl2\nl2\nl2\nl2\nl3\nl3\nl3\nl3\nl4\nl4\nl4\nl4");
testSelection(editor, [[2,2],[2,0,2,1],[6,0,6,1],[10,0,10,1],[14,0,14,1]]); testSelection(editor, [[2,2],[2,1,2,0],[6,0,6,1],[10,0,10,1],[14,0,14,1]]);
exec("movelinesdown", 12); exec("movelinesdown", 12);
assert.equal(editor.getValue(),"l1\nl1\nl1\nl2\nl2\nl2\nl3\nl3\nl3\nl4\nl4\nl4\nl1\nl2\nl3\nl4"); assert.equal(editor.getValue(),"l1\nl1\nl1\nl2\nl2\nl2\nl3\nl3\nl3\nl4\nl4\nl4\nl1\nl2\nl3\nl4");
testSelection(editor, [[12,2],[12,0,12,1],[13,0,13,1],[14,0,14,1],[15,0,15,1]]); testSelection(editor, [[12,2],[12,1,12,0],[13,0,13,1],[14,0,14,1],[15,0,15,1]]);
exec("movelinesup", 12); exec("movelinesup", 12);
assert.equal(editor.getValue(),"l1\nl2\nl3\nl4\nl1\nl1\nl1\nl2\nl2\nl2\nl3\nl3\nl3\nl4\nl4\nl4"); assert.equal(editor.getValue(),"l1\nl2\nl3\nl4\nl1\nl1\nl1\nl2\nl2\nl2\nl3\nl3\nl3\nl4\nl4\nl4");
testSelection(editor, [[0,2],[0,0,0,1],[1,0,1,1],[2,0,2,1],[3,0,3,1]]); testSelection(editor, [[0,2],[0,1,0,0],[1,0,1,1],[2,0,2,1],[3,0,3,1]]);
}, },
"test multiselect fromJSON/toJSON": function() { "test multiselect fromJSON/toJSON": function() {
@ -259,6 +261,20 @@ module.exports = {
selection.fromJSON(after); selection.fromJSON(after);
assert.ok(!selection.isEqual(before)); assert.ok(!selection.isEqual(before));
assert.ok(selection.isEqual(after)); assert.ok(selection.isEqual(after));
},
"test multiselect align": function() {
var doc = new EditSession(["l1", "l2", "l3"]);
doc.setUndoManager(new UndoManager());
editor = new Editor(new MockRenderer(), doc);
var selection = editor.selection;
selection.addRange(new Range(1,0,1,0))
selection.addRange(new Range(2,2,2,2))
editor.execCommand("alignCursors");
assert.equal(' l1\n l2\nl3', editor.getValue());
doc.markUndoGroup();
editor.execCommand("undo");
assert.equal('l1\nl2\nl3', editor.getValue());
} }
}; };

View file

@ -150,28 +150,27 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass)
* Emitted when the place holder updates. * Emitted when the place holder updates.
* *
**/ **/
this.onUpdate = function(event) { this.onUpdate = function(delta) {
var delta = event.data; var range = delta;
var range = delta.range;
if(range.start.row !== range.end.row) return; if(range.start.row !== range.end.row) return;
if(range.start.row !== this.pos.row) return; if(range.start.row !== this.pos.row) return;
if (this.$updating) return; if (this.$updating) return;
this.$updating = true; this.$updating = true;
var lengthDiff = delta.action === "insertText" ? range.end.column - range.start.column : range.start.column - range.end.column; var lengthDiff = delta.action === "insert" ? range.end.column - range.start.column : range.start.column - range.end.column;
if(range.start.column >= this.pos.column && range.start.column <= this.pos.column + this.length + 1) { if(range.start.column >= this.pos.column && range.start.column <= this.pos.column + this.length + 1) {
var distanceFromStart = range.start.column - this.pos.column; var distanceFromStart = range.start.column - this.pos.column;
this.length += lengthDiff; this.length += lengthDiff;
if(!this.session.$fromUndo) { if(!this.session.$fromUndo) {
if(delta.action === "insertText") { if(delta.action === 'insert') {
for (var i = this.others.length - 1; i >= 0; i--) { for (var i = this.others.length - 1; i >= 0; i--) {
var otherPos = this.others[i]; var otherPos = this.others[i];
var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart};
if(otherPos.row === range.start.row && range.start.column < otherPos.column) if(otherPos.row === range.start.row && range.start.column < otherPos.column)
newPos.column += lengthDiff; newPos.column += lengthDiff;
this.doc.insert(newPos, delta.text); this.doc.insertMergedLines(newPos, delta.lines);
} }
} else if(delta.action === "removeText") { } else if(delta.action === 'remove') {
for (var i = this.others.length - 1; i >= 0; i--) { for (var i = this.others.length - 1; i >= 0; i--) {
var otherPos = this.others[i]; var otherPos = this.others[i];
var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart};
@ -181,7 +180,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass)
} }
} }
// Special case: insert in beginning // Special case: insert in beginning
if(range.start.column === this.pos.column && delta.action === "insertText") { if(range.start.column === this.pos.column && delta.action === 'insert') {
setTimeout(function() { setTimeout(function() {
this.pos.setPosition(this.pos.row, this.pos.column - lengthDiff); this.pos.setPosition(this.pos.row, this.pos.column - lengthDiff);
for (var i = 0; i < this.others.length; i++) { for (var i = 0; i < this.others.length; i++) {
@ -193,7 +192,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass)
} }
}.bind(this), 0); }.bind(this), 0);
} }
else if(range.start.column === this.pos.column && delta.action === "removeText") { else if(range.start.column === this.pos.column && delta.action === 'remove') {
setTimeout(function() { setTimeout(function() {
for (var i = 0; i < this.others.length; i++) { for (var i = 0; i < this.others.length; i++) {
var other = this.others[i]; var other = this.others[i];

View file

@ -180,14 +180,13 @@ var RangeList = function() {
this.session = null; this.session = null;
}; };
this.$onChange = function(e) { this.$onChange = function(delta) {
var changeRange = e.data.range; if (delta.action == "insert"){
if (e.data.action[0] == "i"){ var start = delta.start;
var start = changeRange.start; var end = delta.end;
var end = changeRange.end;
} else { } else {
var end = changeRange.start; var end = delta.start;
var start = changeRange.end; var start = delta.end;
} }
var startRow = start.row; var startRow = start.row;
var endRow = end.row; var endRow = end.row;

View file

@ -923,7 +923,7 @@ var Selection = function(session) {
this.toSingleRange(data[0]); this.toSingleRange(data[0]);
for (var i = data.length; i--; ) { for (var i = data.length; i--; ) {
var r = Range.fromPoints(data[i].start, data[i].end); var r = Range.fromPoints(data[i].start, data[i].end);
if (data.isBackwards) if (data[i].isBackwards)
r.cursor = r.start; r.cursor = r.start;
this.addRange(r, true); this.addRange(r, true);
} }

View file

@ -667,11 +667,11 @@ var TabstopManager = function(editor) {
this.editor = null; this.editor = null;
}; };
this.onChange = function(e) { this.onChange = function(delta) {
var changeRange = e.data.range; var changeRange = delta;
var isRemove = e.data.action[0] == "r"; var isRemove = delta.action[0] == "r";
var start = changeRange.start; var start = delta.start;
var end = changeRange.end; var end = delta.end;
var startRow = start.row; var startRow = start.row;
var endRow = end.row; var endRow = end.row;
var lineDif = endRow - startRow; var lineDif = endRow - startRow;

7
lib/ace/snippets/mask.js Normal file
View file

@ -0,0 +1,7 @@
define(function(require, exports, module) {
"use strict";
exports.snippetText = require("../requirejs/text!./mask.snippets");
exports.scope = "mask";
});

View file

7
lib/ace/snippets/nim.js Normal file
View file

@ -0,0 +1,7 @@
define(function(require, exports, module) {
"use strict";
exports.snippetText = require("../requirejs/text!./nim.snippets");
exports.scope = "nim";
});

View file

@ -0,0 +1,130 @@
snippet #!
#!/usr/bin/env nim
snippet imp
import ${1:module}
snippet from
from ${1:package} import ${2:module}
# Module Docstring
snippet docs
## File: ${1:FILENAME:file_name}
## Author: ${2:author}
## Description: ${3}
snippet wh
while ${1:condition}:
${2:# TODO: write code...}
# dowh - does the same as do...while in other languages
snippet dowh
while true:
${1:# TODO: write code...}
if ${2:condition}:
break
snippet with
with ${1:expr} as ${2:var}:
${3:# TODO: write code...}
# New Function
snippet proc
proc ${1:fname}(${2:`indent('.') ? 'self' : ''`}): ${3: return type} =
##${4:docstring for $1}
${5:# TODO: write code...}
snippet deff
def ${1:fname}(${2:`indent('.') ? 'self' : ''`}):
${3:# TODO: write code...}
# New Method
snippet defs
def ${1:mname}(self, ${2:arg}):
${3:# TODO: write code...}
# New Property
snippet property
def ${1:foo}():
doc = "${2:The $1 property.}"
def fget(self):
${3:return self._$1}
def fset(self, value):
${4:self._$1 = value}
# Ifs
snippet if
if ${1:condition}:
${2:# TODO: write code...}
snippet el
else:
${1:# TODO: write code...}
snippet ei
elif ${1:condition}:
${2:# TODO: write code...}
# For
snippet for
for ${1:item} in ${2:items}:
${3:# TODO: write code...}
# Encodes
snippet cutf8
# -*- coding: utf-8 -*-
snippet clatin1
# -*- coding: latin-1 -*-
snippet cascii
# -*- coding: ascii -*-
# Lambda
snippet ld
${1:var} = lambda ${2:vars} : ${3:action}
snippet .
self.
snippet try Try/Except
try:
${1:# TODO: write code...}
except ${2:Exception}, ${3:e}:
${4:raise $3}
snippet try Try/Except/Else
try:
${1:# TODO: write code...}
except ${2:Exception}, ${3:e}:
${4:raise $3}
else:
${5:# TODO: write code...}
snippet try Try/Except/Finally
try:
${1:# TODO: write code...}
except ${2:Exception}, ${3:e}:
${4:raise $3}
finally:
${5:# TODO: write code...}
snippet try Try/Except/Else/Finally
try:
${1:# TODO: write code...}
except ${2:Exception}, ${3:e}:
${4:raise $3}
else:
${5:# TODO: write code...}
finally:
${6:# TODO: write code...}
# if __name__ == '__main__':
snippet ifmain
if isMainModule:
${1:main()}
snippet "
## ${1:doc}
# test function/method
snippet test
def test_${1:description}(${2:self}):
${3:# TODO: write code...}
# test case
snippet testcase
class ${1:ExampleCase}(unittest.TestCase):
def test_${2:description}(self):
${3:# TODO: write code...}
#getopt
snippet getopt
try:
# Short option syntax: "hv:"
# Long option syntax: "help" or "verbose="
opts, args = getopt.getopt(sys.argv[1:], "${1:short_options}", [${2:long_options}])
except getopt.GetoptError, err:
# Print debug info
print str(err)
${3:error_action}
for option, argument in opts:
if option in ("-h", "--help"):
${4}
elif option in ("-v", "--verbose"):
verbose = argument

View file

@ -47,7 +47,7 @@ snippet apply
snippet lapply snippet lapply
lapply(${1:list}, ${2:function}) lapply(${1:list}, ${2:function})
snippet sapply snippet sapply
lapply(${1:list}, ${2:function}) sapply(${1:list}, ${2:function})
snippet vapply snippet vapply
vapply(${1:list}, ${2:function}, ${3:type}) vapply(${1:list}, ${2:function}, ${3:type})
snippet mapply snippet mapply

View file

@ -0,0 +1,7 @@
define(function(require, exports, module) {
"use strict";
exports.snippetText = require("../requirejs/text!./sqlserver.snippets");
exports.scope = "sqlserver";
});

View file

@ -0,0 +1,70 @@
# ISNULL
snippet isnull
ISNULL(${1:check_expression}, ${2:replacement_value})
# FORMAT
snippet format
FORMAT(${1:value}, ${2:format})
# CAST
snippet cast
CAST(${1:expression} AS ${2:data_type})
# CONVERT
snippet convert
CONVERT(${1:data_type}, ${2:expression})
# DATEPART
snippet datepart
DATEPART(${1:datepart}, ${2:date})
# DATEDIFF
snippet datediff
DATEDIFF(${1:datepart}, ${2:startdate}, ${3:enddate})
# DATEADD
snippet dateadd
DATEADD(${1:datepart}, ${2:number}, ${3:date})
# DATEFROMPARTS
snippet datefromparts
DATEFROMPARTS(${1:year}, ${2:month}, ${3:day})
# OBJECT_DEFINITION
snippet objectdef
SELECT OBJECT_DEFINITION(OBJECT_ID('${1:sys.server_permissions /*object name*/}'))
# STUFF XML
snippet stuffxml
STUFF((SELECT ', ' + ${1:ColumnName}
FROM ${2:TableName}
WHERE ${3:WhereClause}
FOR XML PATH('')), 1, 1, '') AS ${4:Alias}
${5:/*https://msdn.microsoft.com/en-us/library/ms188043.aspx*/}
# Create Procedure
snippet createproc
-- =============================================
-- Author: ${1:Author}
-- Create date: ${2:Date}
-- Description: ${3:Description}
-- =============================================
CREATE PROCEDURE ${4:Procedure_Name}
${5:/*Add the parameters for the stored procedure here*/}
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
SET NOCOUNT ON;
${6:/*Add the T-SQL statements to compute the return value here*/}
END
GO
# Create Scalar Function
snippet createfn
-- =============================================
-- Author: ${1:Author}
-- Create date: ${2:Date}
-- Description: ${3:Description}
-- =============================================
CREATE FUNCTION ${4:Scalar_Function_Name}
-- Add the parameters for the function here
RETURNS ${5:Function_Data_Type}
AS
BEGIN
DECLARE @Result ${5:Function_Data_Type}
${6:/*Add the T-SQL statements to compute the return value here*/}
END
GO

View file

@ -23,7 +23,6 @@
.ace-clouds.ace_multiselect .ace_selection.ace_start { .ace-clouds.ace_multiselect .ace_selection.ace_start {
box-shadow: 0 0 3px 0px #FFFFFF; box-shadow: 0 0 3px 0px #FFFFFF;
border-radius: 2px
} }
.ace-clouds .ace_marker-layer .ace_step { .ace-clouds .ace_marker-layer .ace_step {

View file

@ -23,7 +23,6 @@
.ace-clouds-midnight.ace_multiselect .ace_selection.ace_start { .ace-clouds-midnight.ace_multiselect .ace_selection.ace_start {
box-shadow: 0 0 3px 0px #191919; box-shadow: 0 0 3px 0px #191919;
border-radius: 2px
} }
.ace-clouds-midnight .ace_marker-layer .ace_step { .ace-clouds-midnight .ace_marker-layer .ace_step {
@ -48,7 +47,7 @@
} }
.ace-clouds-midnight .ace_invisible { .ace-clouds-midnight .ace_invisible {
color: #BFBFBF color: #666
} }
.ace-clouds-midnight .ace_keyword, .ace-clouds-midnight .ace_keyword,

View file

@ -5,7 +5,7 @@
.ace-cobalt .ace_print-margin { .ace-cobalt .ace_print-margin {
width: 1px; width: 1px;
background: #011e3a background: #555555
} }
.ace-cobalt { .ace-cobalt {
@ -23,7 +23,6 @@
.ace-cobalt.ace_multiselect .ace_selection.ace_start { .ace-cobalt.ace_multiselect .ace_selection.ace_start {
box-shadow: 0 0 3px 0px #002240; box-shadow: 0 0 3px 0px #002240;
border-radius: 2px
} }
.ace-cobalt .ace_marker-layer .ace_step { .ace-cobalt .ace_marker-layer .ace_step {
@ -131,4 +130,4 @@
.ace-cobalt .ace_indent-guide { .ace-cobalt .ace_indent-guide {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHCLSvkPAAP3AgSDTRd4AAAAAElFTkSuQmCC) right repeat-y background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHCLSvkPAAP3AgSDTRd4AAAAAElFTkSuQmCC) right repeat-y
} }

View file

@ -23,7 +23,6 @@
.ace-dawn.ace_multiselect .ace_selection.ace_start { .ace-dawn.ace_multiselect .ace_selection.ace_start {
box-shadow: 0 0 3px 0px #F9F9F9; box-shadow: 0 0 3px 0px #F9F9F9;
border-radius: 2px
} }
.ace-dawn .ace_marker-layer .ace_step { .ace-dawn .ace_marker-layer .ace_step {

Some files were not shown because too many files have changed in this diff Show more