mdbe 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (688) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +53 -0
  4. data/app.rb +182 -0
  5. data/bin/mdbe +5 -0
  6. data/config.ru +2 -0
  7. data/environment.rb +8 -0
  8. data/lib/mdbe.rb +39 -0
  9. data/lib/mdbe/action_controller_debug_patch.rb +12 -0
  10. data/lib/mdbe/code_evaluation.rb +46 -0
  11. data/lib/mdbe/database_views.rb +24 -0
  12. data/lib/mdbe/database_views/abstract_dictionary.rb +69 -0
  13. data/lib/mdbe/database_views/abstract_exception.rb +25 -0
  14. data/lib/mdbe/database_views/array.rb +28 -0
  15. data/lib/mdbe/database_views/boolean.rb +12 -0
  16. data/lib/mdbe/database_views/class.rb +46 -0
  17. data/lib/mdbe/database_views/exception.rb +3 -0
  18. data/lib/mdbe/database_views/execblock.rb +5 -0
  19. data/lib/mdbe/database_views/fixnum.rb +5 -0
  20. data/lib/mdbe/database_views/float.rb +5 -0
  21. data/lib/mdbe/database_views/globals.rb +2 -0
  22. data/lib/mdbe/database_views/gsnmethod.rb +29 -0
  23. data/lib/mdbe/database_views/hash.rb +5 -0
  24. data/lib/mdbe/database_views/maglev_record.rb +42 -0
  25. data/lib/mdbe/database_views/module.rb +103 -0
  26. data/lib/mdbe/database_views/nilclass.rb +5 -0
  27. data/lib/mdbe/database_views/object.rb +80 -0
  28. data/lib/mdbe/database_views/proc.rb +3 -0
  29. data/lib/mdbe/database_views/repository.rb +3 -0
  30. data/lib/mdbe/database_views/ruby_workspace.rb +5 -0
  31. data/lib/mdbe/database_views/smalltalk_classes.rb +34 -0
  32. data/lib/mdbe/database_views/smalltalk_classes.st +60 -0
  33. data/lib/mdbe/database_views/string.rb +31 -0
  34. data/lib/mdbe/database_views/symbol.rb +32 -0
  35. data/lib/mdbe/database_views/system.rb +61 -0
  36. data/lib/mdbe/database_views/thread.rb +101 -0
  37. data/lib/mdbe/debug_server.rb +22 -0
  38. data/lib/mdbe/halt.rb +42 -0
  39. data/lib/mdbe/ruby_workspace.rb +29 -0
  40. data/lib/mdbe/version.rb +3 -0
  41. data/lib/tasks/maglev-database-explorer_tasks.rake +4 -0
  42. data/public/LICENSE +35 -0
  43. data/public/amber/CHANGELOG +65 -0
  44. data/public/amber/LICENSE +22 -0
  45. data/public/amber/Makefile +53 -0
  46. data/public/amber/README.md +30 -0
  47. data/public/amber/bin/amber +3 -0
  48. data/public/amber/bin/amberc +352 -0
  49. data/public/amber/bin/nodecompile.js +33 -0
  50. data/public/amber/bin/server +3 -0
  51. data/public/amber/bin/server.bat +3 -0
  52. data/public/amber/css/amber-normalize.css +468 -0
  53. data/public/amber/css/amber-normalize.less +501 -0
  54. data/public/amber/css/amber.css +539 -0
  55. data/public/amber/css/documentation.css +84 -0
  56. data/public/amber/css/profstef.css +75 -0
  57. data/public/amber/css/style.css +313 -0
  58. data/public/amber/documentation.html +37 -0
  59. data/public/amber/examples/Makefile +23 -0
  60. data/public/amber/examples/README +4 -0
  61. data/public/amber/examples/android/helloamber/AndroidManifest.xml +19 -0
  62. data/public/amber/examples/android/helloamber/HelloAmber.st +13 -0
  63. data/public/amber/examples/android/helloamber/Makefile +56 -0
  64. data/public/amber/examples/android/helloamber/README.md +80 -0
  65. data/public/amber/examples/android/helloamber/ant.properties +17 -0
  66. data/public/amber/examples/android/helloamber/assets/index.html +15 -0
  67. data/public/amber/examples/android/helloamber/assets/jquery-1.7.2.min.js +4 -0
  68. data/public/amber/examples/android/helloamber/build.xml +83 -0
  69. data/public/amber/examples/android/helloamber/local.properties +10 -0
  70. data/public/amber/examples/android/helloamber/proguard-project.txt +20 -0
  71. data/public/amber/examples/android/helloamber/project.properties +14 -0
  72. data/public/amber/examples/android/helloamber/res/layout/main.xml +6 -0
  73. data/public/amber/examples/android/helloamber/res/values/strings.xml +4 -0
  74. data/public/amber/examples/android/helloamber/src/org/amberlang/android/helloamber/HelloAmber.java +59 -0
  75. data/public/amber/examples/myproject/index.html +16 -0
  76. data/public/amber/examples/nodejs/README +9 -0
  77. data/public/amber/examples/nodejs/benchfib/Benchfib.st +124 -0
  78. data/public/amber/examples/nodejs/benchfib/Makefile +8 -0
  79. data/public/amber/examples/nodejs/benchfib/benchfib +1 -0
  80. data/public/amber/examples/nodejs/hello/Hello.st +9 -0
  81. data/public/amber/examples/nodejs/hello/Makefile +8 -0
  82. data/public/amber/examples/nodejs/hello/README +13 -0
  83. data/public/amber/examples/nodejs/hello/hello +1 -0
  84. data/public/amber/examples/nodejs/meta/Makefile +8 -0
  85. data/public/amber/examples/nodejs/meta/MyScript.st +27 -0
  86. data/public/amber/examples/nodejs/meta/meta +1 -0
  87. data/public/amber/examples/nodejs/pystone/Makefile +8 -0
  88. data/public/amber/examples/nodejs/pystone/Pystone.st +306 -0
  89. data/public/amber/examples/nodejs/pystone/pystone +1 -0
  90. data/public/amber/examples/nodejs/trivialserver/Makefile +8 -0
  91. data/public/amber/examples/nodejs/trivialserver/TrivialServer.st +51 -0
  92. data/public/amber/examples/nodejs/trivialserver/trivial +1 -0
  93. data/public/amber/examples/presentation/esug2011/images/asterix.png +0 -0
  94. data/public/amber/examples/presentation/esug2011/images/background_box.png +0 -0
  95. data/public/amber/examples/presentation/esug2011/images/background_header.png +0 -0
  96. data/public/amber/examples/presentation/esug2011/images/balloon.jpg +0 -0
  97. data/public/amber/examples/presentation/esug2011/images/balloon_header.png +0 -0
  98. data/public/amber/examples/presentation/esug2011/images/devices.jpg +0 -0
  99. data/public/amber/examples/presentation/esug2011/images/enyo.png +0 -0
  100. data/public/amber/examples/presentation/esug2011/images/ide_star_wars.png +0 -0
  101. data/public/amber/examples/presentation/esug2011/images/nodejs.png +0 -0
  102. data/public/amber/examples/presentation/esug2011/images/terminal.png +0 -0
  103. data/public/amber/examples/presentation/esug2011/images/webos.png +0 -0
  104. data/public/amber/examples/presentation/fosdem2012/images/amber.png +0 -0
  105. data/public/amber/examples/presentation/fosdem2012/images/ambrhino.jpg +0 -0
  106. data/public/amber/examples/presentation/fosdem2012/images/nodejs.png +0 -0
  107. data/public/amber/examples/presentation/fosdem2012/images/pharo.png +0 -0
  108. data/public/amber/examples/presentation/fosdem2012/images/php.gif +0 -0
  109. data/public/amber/examples/presentation/fosdem2012/images/rails.png +0 -0
  110. data/public/amber/examples/presentation/fosdem2012/lib/booklet/images/arrow-next.png +0 -0
  111. data/public/amber/examples/presentation/fosdem2012/lib/booklet/images/arrow-prev.png +0 -0
  112. data/public/amber/examples/presentation/fosdem2012/lib/booklet/images/closedhand.cur +0 -0
  113. data/public/amber/examples/presentation/fosdem2012/lib/booklet/images/openhand.cur +0 -0
  114. data/public/amber/examples/presentation/fosdem2012/lib/booklet/images/shadow-top-back.png +0 -0
  115. data/public/amber/examples/presentation/fosdem2012/lib/booklet/images/shadow-top-forward.png +0 -0
  116. data/public/amber/examples/presentation/fosdem2012/lib/booklet/images/shadow.png +0 -0
  117. data/public/amber/examples/presentation/fosdem2012/lib/booklet/jquery.booklet.1.2.0.css +100 -0
  118. data/public/amber/examples/presentation/fosdem2012/lib/booklet/jquery.booklet.1.2.0.js +1232 -0
  119. data/public/amber/examples/presentation/fosdem2012/lib/booklet/jquery.booklet.1.2.0.min.js +13 -0
  120. data/public/amber/examples/presentation/fosdem2012/lib/booklet/jquery.easing.1.3.js +38 -0
  121. data/public/amber/examples/presentation/index.html +17 -0
  122. data/public/amber/examples/presentation/js/Presentation.deploy.js +1922 -0
  123. data/public/amber/examples/presentation/js/Presentation.js +2712 -0
  124. data/public/amber/examples/presentation/st/Presentation.st +1996 -0
  125. data/public/amber/examples/trysmalltalk/index.html +18 -0
  126. data/public/amber/examples/trysmalltalk/js/TrySmalltalk.deploy.js +837 -0
  127. data/public/amber/examples/trysmalltalk/js/TrySmalltalk.js +1206 -0
  128. data/public/amber/examples/trysmalltalk/st/TrySmalltalk.st +964 -0
  129. data/public/amber/examples/twitterwall/css/twitterwall.css +19 -0
  130. data/public/amber/examples/twitterwall/index.html +35 -0
  131. data/public/amber/examples/twitterwall/js/TwitterWall.deploy.js +116 -0
  132. data/public/amber/examples/twitterwall/js/TwitterWall.js +146 -0
  133. data/public/amber/examples/twitterwall/st/TwitterWall.st +91 -0
  134. data/public/amber/examples/webos/README +11 -0
  135. data/public/amber/examples/webos/eris/DuckQwaq.wav +0 -0
  136. data/public/amber/examples/webos/eris/EnyoAmber.st +36 -0
  137. data/public/amber/examples/webos/eris/Eris.css +0 -0
  138. data/public/amber/examples/webos/eris/Eris.st +86 -0
  139. data/public/amber/examples/webos/eris/Makefile +37 -0
  140. data/public/amber/examples/webos/eris/README +3 -0
  141. data/public/amber/examples/webos/eris/appinfo.json +10 -0
  142. data/public/amber/examples/webos/eris/index.html +12 -0
  143. data/public/amber/examples/webos/helloamber/EnyoAmber.st +36 -0
  144. data/public/amber/examples/webos/helloamber/HelloAmber.st +86 -0
  145. data/public/amber/examples/webos/helloamber/Makefile +38 -0
  146. data/public/amber/examples/webos/helloamber/README +5 -0
  147. data/public/amber/examples/webos/helloamber/appinfo.json +10 -0
  148. data/public/amber/examples/webos/helloamber/index.html +12 -0
  149. data/public/amber/favicon.ico +0 -0
  150. data/public/amber/images/amber.png +0 -0
  151. data/public/amber/images/amber.svg +706 -0
  152. data/public/amber/images/amber_small.png +0 -0
  153. data/public/amber/images/off.amber.png +0 -0
  154. data/public/amber/images/off.png +0 -0
  155. data/public/amber/images/offHover.amber.png +0 -0
  156. data/public/amber/images/offHover.png +0 -0
  157. data/public/amber/images/presentation.png +0 -0
  158. data/public/amber/images/profstef.png +0 -0
  159. data/public/amber/images/sprite.amber.png +0 -0
  160. data/public/amber/images/sprite.png +0 -0
  161. data/public/amber/images/tinylogo.amber.png +0 -0
  162. data/public/amber/images/tinylogo.png +0 -0
  163. data/public/amber/images/twitterwall.png +0 -0
  164. data/public/amber/index.html +55 -0
  165. data/public/amber/js/Additional-Examples.deploy.js +15 -0
  166. data/public/amber/js/Additional-Examples.js +21 -0
  167. data/public/amber/js/Benchfib.deploy.js +132 -0
  168. data/public/amber/js/Benchfib.js +167 -0
  169. data/public/amber/js/Canvas.deploy.js +2446 -0
  170. data/public/amber/js/Canvas.js +3547 -0
  171. data/public/amber/js/Compiler-Tests.deploy.js +97 -0
  172. data/public/amber/js/Compiler-Tests.js +137 -0
  173. data/public/amber/js/Compiler.deploy.js +1877 -0
  174. data/public/amber/js/Compiler.js +2622 -0
  175. data/public/amber/js/Documentation.deploy.js +961 -0
  176. data/public/amber/js/Documentation.js +1376 -0
  177. data/public/amber/js/Examples.deploy.js +53 -0
  178. data/public/amber/js/Examples.js +73 -0
  179. data/public/amber/js/IDE.deploy.js +3557 -0
  180. data/public/amber/js/IDE.js +5002 -0
  181. data/public/amber/js/Kernel-Announcements.deploy.js +107 -0
  182. data/public/amber/js/Kernel-Announcements.js +152 -0
  183. data/public/amber/js/Kernel-Classes.deploy.js +774 -0
  184. data/public/amber/js/Kernel-Classes.js +1095 -0
  185. data/public/amber/js/Kernel-Collections.deploy.js +3121 -0
  186. data/public/amber/js/Kernel-Collections.js +4427 -0
  187. data/public/amber/js/Kernel-Exceptions.deploy.js +244 -0
  188. data/public/amber/js/Kernel-Exceptions.js +349 -0
  189. data/public/amber/js/Kernel-Methods.deploy.js +573 -0
  190. data/public/amber/js/Kernel-Methods.js +807 -0
  191. data/public/amber/js/Kernel-Objects.deploy.js +2877 -0
  192. data/public/amber/js/Kernel-Objects.js +4107 -0
  193. data/public/amber/js/Kernel-Tests.deploy.js +1513 -0
  194. data/public/amber/js/Kernel-Tests.js +2053 -0
  195. data/public/amber/js/Kernel-Transcript.deploy.js +142 -0
  196. data/public/amber/js/Kernel-Transcript.js +202 -0
  197. data/public/amber/js/Maglev-Core.deploy.js +2996 -0
  198. data/public/amber/js/Maglev-Core.js +4246 -0
  199. data/public/amber/js/Maglev-Database-Explorer.deploy.js +4476 -0
  200. data/public/amber/js/Maglev-Database-Explorer.js +6232 -0
  201. data/public/amber/js/Maglev-Vendor.deploy.js +350 -0
  202. data/public/amber/js/Maglev-Vendor.js +465 -0
  203. data/public/amber/js/README.md +5 -0
  204. data/public/amber/js/SUnit.deploy.js +351 -0
  205. data/public/amber/js/SUnit.js +501 -0
  206. data/public/amber/js/amber.js +273 -0
  207. data/public/amber/js/boot.js +602 -0
  208. data/public/amber/js/compat.js +22 -0
  209. data/public/amber/js/init.js +9 -0
  210. data/public/amber/js/lib/CodeMirror/LICENSE +19 -0
  211. data/public/amber/js/lib/CodeMirror/active-line.js +39 -0
  212. data/public/amber/js/lib/CodeMirror/amber.css +21 -0
  213. data/public/amber/js/lib/CodeMirror/codemirror.css +67 -0
  214. data/public/amber/js/lib/CodeMirror/codemirror.js +2144 -0
  215. data/public/amber/js/lib/CodeMirror/smalltalk.js +134 -0
  216. data/public/amber/js/lib/jQuery/jquery-1.4.4.min.js +167 -0
  217. data/public/amber/js/lib/jQuery/jquery-1.6.4.min.js +4 -0
  218. data/public/amber/js/lib/jQuery/jquery-ui-1.8.16.custom.min.js +791 -0
  219. data/public/amber/js/lib/jQuery/jquery.textarea.js +267 -0
  220. data/public/amber/js/lib/peg-0.6.2.min.js +2 -0
  221. data/public/amber/js/lib/showdown.js +419 -0
  222. data/public/amber/js/parser.js +4222 -0
  223. data/public/amber/js/parser.pegjs +223 -0
  224. data/public/amber/learn.html +40 -0
  225. data/public/amber/repl/Makefile +8 -0
  226. data/public/amber/repl/REPL.js +124 -0
  227. data/public/amber/repl/REPL.st +56 -0
  228. data/public/amber/repl/amber.js +18085 -0
  229. data/public/amber/server/FileServer.st +576 -0
  230. data/public/amber/server/Makefile +8 -0
  231. data/public/amber/server/server.js +13049 -0
  232. data/public/amber/st/Benchfib.js +297 -0
  233. data/public/amber/st/Benchfib.st +124 -0
  234. data/public/amber/st/Canvas.st +968 -0
  235. data/public/amber/st/Compiler-Tests.st +471 -0
  236. data/public/amber/st/Compiler.st +1445 -0
  237. data/public/amber/st/Documentation.st +758 -0
  238. data/public/amber/st/Examples.js +100 -0
  239. data/public/amber/st/Examples.st +38 -0
  240. data/public/amber/st/IDE.st +2404 -0
  241. data/public/amber/st/Kernel-Announcements.st +61 -0
  242. data/public/amber/st/Kernel-Classes.st +462 -0
  243. data/public/amber/st/Kernel-Collections.st +1611 -0
  244. data/public/amber/st/Kernel-Exceptions.st +124 -0
  245. data/public/amber/st/Kernel-Methods.st +291 -0
  246. data/public/amber/st/Kernel-Objects.st +1587 -0
  247. data/public/amber/st/Kernel-Tests.st +953 -0
  248. data/public/amber/st/Kernel-Transcript.st +70 -0
  249. data/public/amber/st/Maglev-Core.st +1694 -0
  250. data/public/amber/st/Maglev-Database-Explorer.st +3148 -0
  251. data/public/amber/st/Maglev-Vendor.st +151 -0
  252. data/public/amber/st/Makefile +104 -0
  253. data/public/amber/st/README.md +4 -0
  254. data/public/amber/st/SUnit.st +172 -0
  255. data/public/css/bootstrap-combined.no-icons.min.css +731 -0
  256. data/public/css/bootstrap.css +6811 -0
  257. data/public/css/images/animated-overlay.gif +0 -0
  258. data/public/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  259. data/public/css/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  260. data/public/css/images/ui-bg_flat_10_000000_40x100.png +0 -0
  261. data/public/css/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  262. data/public/css/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  263. data/public/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  264. data/public/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  265. data/public/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  266. data/public/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  267. data/public/css/images/ui-icons_222222_256x240.png +0 -0
  268. data/public/css/images/ui-icons_228ef1_256x240.png +0 -0
  269. data/public/css/images/ui-icons_ef8c08_256x240.png +0 -0
  270. data/public/css/images/ui-icons_ffd27a_256x240.png +0 -0
  271. data/public/css/images/ui-icons_ffffff_256x240.png +0 -0
  272. data/public/css/jquery-ui.min.css +5 -0
  273. data/public/css/smalltalk_code.css +42 -0
  274. data/public/css/style.css +210 -0
  275. data/public/images/bg_tile.png +0 -0
  276. data/public/images/maglev-logo.gif +0 -0
  277. data/public/images/mchammer.gif +0 -0
  278. data/public/images/rails_tiny.png +0 -0
  279. data/public/images/ruby.png +0 -0
  280. data/public/images/ruby_smalltalk_bridge.png +0 -0
  281. data/public/images/smalltalk.png +0 -0
  282. data/public/img/glyphicons-halflings.png +0 -0
  283. data/public/index.html +118 -0
  284. data/public/libs/bootstrap.min.js +7 -0
  285. data/public/libs/codemirror/CONTRIBUTING.md +72 -0
  286. data/public/libs/codemirror/LICENSE +23 -0
  287. data/public/libs/codemirror/README.md +11 -0
  288. data/public/libs/codemirror/addon/dialog/dialog.css +32 -0
  289. data/public/libs/codemirror/addon/dialog/dialog.js +80 -0
  290. data/public/libs/codemirror/addon/display/placeholder.js +54 -0
  291. data/public/libs/codemirror/addon/edit/closebrackets.js +54 -0
  292. data/public/libs/codemirror/addon/edit/closetag.js +86 -0
  293. data/public/libs/codemirror/addon/edit/continuecomment.js +44 -0
  294. data/public/libs/codemirror/addon/edit/continuelist.js +25 -0
  295. data/public/libs/codemirror/addon/edit/matchbrackets.js +82 -0
  296. data/public/libs/codemirror/addon/fold/brace-fold.js +31 -0
  297. data/public/libs/codemirror/addon/fold/foldcode.js +32 -0
  298. data/public/libs/codemirror/addon/fold/indent-fold.js +11 -0
  299. data/public/libs/codemirror/addon/fold/xml-fold.js +64 -0
  300. data/public/libs/codemirror/addon/hint/html-hint.js +582 -0
  301. data/public/libs/codemirror/addon/hint/javascript-hint.js +142 -0
  302. data/public/libs/codemirror/addon/hint/pig-hint.js +117 -0
  303. data/public/libs/codemirror/addon/hint/python-hint.js +93 -0
  304. data/public/libs/codemirror/addon/hint/show-hint.css +38 -0
  305. data/public/libs/codemirror/addon/hint/show-hint.js +180 -0
  306. data/public/libs/codemirror/addon/hint/xml-hint.js +118 -0
  307. data/public/libs/codemirror/addon/lint/javascript-lint.js +127 -0
  308. data/public/libs/codemirror/addon/lint/json-lint.js +14 -0
  309. data/public/libs/codemirror/addon/lint/lint.css +96 -0
  310. data/public/libs/codemirror/addon/lint/lint.js +197 -0
  311. data/public/libs/codemirror/addon/mode/loadmode.js +51 -0
  312. data/public/libs/codemirror/addon/mode/multiplex.js +95 -0
  313. data/public/libs/codemirror/addon/mode/overlay.js +59 -0
  314. data/public/libs/codemirror/addon/runmode/colorize.js +29 -0
  315. data/public/libs/codemirror/addon/runmode/runmode-standalone.js +130 -0
  316. data/public/libs/codemirror/addon/runmode/runmode.js +52 -0
  317. data/public/libs/codemirror/addon/runmode/runmode.node.js +89 -0
  318. data/public/libs/codemirror/addon/search/match-highlighter.js +60 -0
  319. data/public/libs/codemirror/addon/search/search.js +131 -0
  320. data/public/libs/codemirror/addon/search/searchcursor.js +133 -0
  321. data/public/libs/codemirror/addon/selection/active-line.js +39 -0
  322. data/public/libs/codemirror/addon/selection/mark-selection.js +34 -0
  323. data/public/libs/codemirror/bin/compress +91 -0
  324. data/public/libs/codemirror/bin/lint +11 -0
  325. data/public/libs/codemirror/demo/activeline.html +70 -0
  326. data/public/libs/codemirror/demo/bidi.html +61 -0
  327. data/public/libs/codemirror/demo/btree.html +87 -0
  328. data/public/libs/codemirror/demo/buffers.html +98 -0
  329. data/public/libs/codemirror/demo/changemode.html +50 -0
  330. data/public/libs/codemirror/demo/closebrackets.html +63 -0
  331. data/public/libs/codemirror/demo/closetag.html +37 -0
  332. data/public/libs/codemirror/demo/complete.html +70 -0
  333. data/public/libs/codemirror/demo/emacs.html +60 -0
  334. data/public/libs/codemirror/demo/folding.html +69 -0
  335. data/public/libs/codemirror/demo/fullscreen.html +147 -0
  336. data/public/libs/codemirror/demo/html5complete.html +92 -0
  337. data/public/libs/codemirror/demo/indentwrap.html +49 -0
  338. data/public/libs/codemirror/demo/lint.html +90 -0
  339. data/public/libs/codemirror/demo/loadmode.html +40 -0
  340. data/public/libs/codemirror/demo/marker.html +59 -0
  341. data/public/libs/codemirror/demo/markselection.html +36 -0
  342. data/public/libs/codemirror/demo/matchhighlighter.html +38 -0
  343. data/public/libs/codemirror/demo/multiplex.html +60 -0
  344. data/public/libs/codemirror/demo/mustache.html +59 -0
  345. data/public/libs/codemirror/demo/placeholder.html +36 -0
  346. data/public/libs/codemirror/demo/preview.html +76 -0
  347. data/public/libs/codemirror/demo/resize.html +49 -0
  348. data/public/libs/codemirror/demo/runmode.html +50 -0
  349. data/public/libs/codemirror/demo/search.html +85 -0
  350. data/public/libs/codemirror/demo/spanaffectswrapping_shim.html +73 -0
  351. data/public/libs/codemirror/demo/theme.html +89 -0
  352. data/public/libs/codemirror/demo/variableheight.html +52 -0
  353. data/public/libs/codemirror/demo/vim.html +65 -0
  354. data/public/libs/codemirror/demo/visibletabs.html +53 -0
  355. data/public/libs/codemirror/demo/widget.html +74 -0
  356. data/public/libs/codemirror/demo/xmlcomplete.html +81 -0
  357. data/public/libs/codemirror/index.html +487 -0
  358. data/public/libs/codemirror/keymap/emacs.js +30 -0
  359. data/public/libs/codemirror/keymap/vim.js +3044 -0
  360. data/public/libs/codemirror/lib/codemirror.css +253 -0
  361. data/public/libs/codemirror/lib/codemirror.js +5585 -0
  362. data/public/libs/codemirror/mode/apl/apl.js +160 -0
  363. data/public/libs/codemirror/mode/apl/index.html +61 -0
  364. data/public/libs/codemirror/mode/asterisk/asterisk.js +183 -0
  365. data/public/libs/codemirror/mode/asterisk/index.html +142 -0
  366. data/public/libs/codemirror/mode/clike/clike.js +302 -0
  367. data/public/libs/codemirror/mode/clike/index.html +103 -0
  368. data/public/libs/codemirror/mode/clike/scala.html +767 -0
  369. data/public/libs/codemirror/mode/clojure/clojure.js +222 -0
  370. data/public/libs/codemirror/mode/clojure/index.html +76 -0
  371. data/public/libs/codemirror/mode/coffeescript/LICENSE +22 -0
  372. data/public/libs/codemirror/mode/coffeescript/coffeescript.js +346 -0
  373. data/public/libs/codemirror/mode/coffeescript/index.html +728 -0
  374. data/public/libs/codemirror/mode/commonlisp/commonlisp.js +101 -0
  375. data/public/libs/codemirror/mode/commonlisp/index.html +165 -0
  376. data/public/libs/codemirror/mode/css/css.js +567 -0
  377. data/public/libs/codemirror/mode/css/index.html +58 -0
  378. data/public/libs/codemirror/mode/css/scss.html +145 -0
  379. data/public/libs/codemirror/mode/css/scss_test.js +80 -0
  380. data/public/libs/codemirror/mode/css/test.js +113 -0
  381. data/public/libs/codemirror/mode/d/d.js +205 -0
  382. data/public/libs/codemirror/mode/d/index.html +262 -0
  383. data/public/libs/codemirror/mode/diff/diff.js +32 -0
  384. data/public/libs/codemirror/mode/diff/index.html +105 -0
  385. data/public/libs/codemirror/mode/ecl/ecl.js +192 -0
  386. data/public/libs/codemirror/mode/ecl/index.html +39 -0
  387. data/public/libs/codemirror/mode/erlang/erlang.js +463 -0
  388. data/public/libs/codemirror/mode/erlang/index.html +64 -0
  389. data/public/libs/codemirror/mode/gas/gas.js +326 -0
  390. data/public/libs/codemirror/mode/gas/index.html +57 -0
  391. data/public/libs/codemirror/mode/gfm/gfm.js +96 -0
  392. data/public/libs/codemirror/mode/gfm/index.html +74 -0
  393. data/public/libs/codemirror/mode/gfm/test.js +112 -0
  394. data/public/libs/codemirror/mode/go/go.js +165 -0
  395. data/public/libs/codemirror/mode/go/index.html +74 -0
  396. data/public/libs/codemirror/mode/groovy/groovy.js +210 -0
  397. data/public/libs/codemirror/mode/groovy/index.html +73 -0
  398. data/public/libs/codemirror/mode/haskell/haskell.js +242 -0
  399. data/public/libs/codemirror/mode/haskell/index.html +62 -0
  400. data/public/libs/codemirror/mode/haxe/haxe.js +429 -0
  401. data/public/libs/codemirror/mode/haxe/index.html +90 -0
  402. data/public/libs/codemirror/mode/htmlembedded/htmlembedded.js +73 -0
  403. data/public/libs/codemirror/mode/htmlembedded/index.html +49 -0
  404. data/public/libs/codemirror/mode/htmlmixed/htmlmixed.js +104 -0
  405. data/public/libs/codemirror/mode/htmlmixed/index.html +73 -0
  406. data/public/libs/codemirror/mode/http/http.js +98 -0
  407. data/public/libs/codemirror/mode/http/index.html +32 -0
  408. data/public/libs/codemirror/mode/javascript/index.html +92 -0
  409. data/public/libs/codemirror/mode/javascript/javascript.js +467 -0
  410. data/public/libs/codemirror/mode/javascript/typescript.html +48 -0
  411. data/public/libs/codemirror/mode/jinja2/index.html +38 -0
  412. data/public/libs/codemirror/mode/jinja2/jinja2.js +42 -0
  413. data/public/libs/codemirror/mode/less/index.html +741 -0
  414. data/public/libs/codemirror/mode/less/less.js +266 -0
  415. data/public/libs/codemirror/mode/livescript/LICENSE +23 -0
  416. data/public/libs/codemirror/mode/livescript/index.html +446 -0
  417. data/public/libs/codemirror/mode/livescript/livescript.js +267 -0
  418. data/public/libs/codemirror/mode/livescript/livescript.ls +266 -0
  419. data/public/libs/codemirror/mode/lua/index.html +74 -0
  420. data/public/libs/codemirror/mode/lua/lua.js +140 -0
  421. data/public/libs/codemirror/mode/markdown/index.html +344 -0
  422. data/public/libs/codemirror/mode/markdown/markdown.js +526 -0
  423. data/public/libs/codemirror/mode/markdown/test.js +636 -0
  424. data/public/libs/codemirror/mode/meta.js +75 -0
  425. data/public/libs/codemirror/mode/mirc/index.html +149 -0
  426. data/public/libs/codemirror/mode/mirc/mirc.js +177 -0
  427. data/public/libs/codemirror/mode/ntriples/index.html +33 -0
  428. data/public/libs/codemirror/mode/ntriples/ntriples.js +170 -0
  429. data/public/libs/codemirror/mode/ocaml/index.html +131 -0
  430. data/public/libs/codemirror/mode/ocaml/ocaml.js +113 -0
  431. data/public/libs/codemirror/mode/pascal/LICENSE +7 -0
  432. data/public/libs/codemirror/mode/pascal/index.html +48 -0
  433. data/public/libs/codemirror/mode/pascal/pascal.js +94 -0
  434. data/public/libs/codemirror/mode/perl/LICENSE +19 -0
  435. data/public/libs/codemirror/mode/perl/index.html +62 -0
  436. data/public/libs/codemirror/mode/perl/perl.js +816 -0
  437. data/public/libs/codemirror/mode/php/index.html +51 -0
  438. data/public/libs/codemirror/mode/php/php.js +129 -0
  439. data/public/libs/codemirror/mode/pig/index.html +42 -0
  440. data/public/libs/codemirror/mode/pig/pig.js +171 -0
  441. data/public/libs/codemirror/mode/properties/index.html +41 -0
  442. data/public/libs/codemirror/mode/properties/properties.js +63 -0
  443. data/public/libs/codemirror/mode/python/LICENSE.txt +21 -0
  444. data/public/libs/codemirror/mode/python/index.html +135 -0
  445. data/public/libs/codemirror/mode/python/python.js +340 -0
  446. data/public/libs/codemirror/mode/q/index.html +131 -0
  447. data/public/libs/codemirror/mode/q/q.js +124 -0
  448. data/public/libs/codemirror/mode/r/LICENSE +24 -0
  449. data/public/libs/codemirror/mode/r/index.html +74 -0
  450. data/public/libs/codemirror/mode/r/r.js +141 -0
  451. data/public/libs/codemirror/mode/rpm/changes/changes.js +19 -0
  452. data/public/libs/codemirror/mode/rpm/changes/index.html +53 -0
  453. data/public/libs/codemirror/mode/rpm/spec/index.html +99 -0
  454. data/public/libs/codemirror/mode/rpm/spec/spec.css +5 -0
  455. data/public/libs/codemirror/mode/rpm/spec/spec.js +66 -0
  456. data/public/libs/codemirror/mode/rst/LICENSE.txt +21 -0
  457. data/public/libs/codemirror/mode/rst/index.html +524 -0
  458. data/public/libs/codemirror/mode/rst/rst.js +550 -0
  459. data/public/libs/codemirror/mode/ruby/LICENSE +24 -0
  460. data/public/libs/codemirror/mode/ruby/index.html +173 -0
  461. data/public/libs/codemirror/mode/ruby/ruby.js +197 -0
  462. data/public/libs/codemirror/mode/rust/index.html +48 -0
  463. data/public/libs/codemirror/mode/rust/rust.js +432 -0
  464. data/public/libs/codemirror/mode/sass/index.html +54 -0
  465. data/public/libs/codemirror/mode/sass/sass.js +349 -0
  466. data/public/libs/codemirror/mode/scheme/index.html +65 -0
  467. data/public/libs/codemirror/mode/scheme/scheme.js +230 -0
  468. data/public/libs/codemirror/mode/shell/index.html +51 -0
  469. data/public/libs/codemirror/mode/shell/shell.js +118 -0
  470. data/public/libs/codemirror/mode/sieve/LICENSE +19 -0
  471. data/public/libs/codemirror/mode/sieve/index.html +81 -0
  472. data/public/libs/codemirror/mode/sieve/sieve.js +183 -0
  473. data/public/libs/codemirror/mode/smalltalk/index.html +57 -0
  474. data/public/libs/codemirror/mode/smalltalk/smalltalk.js +141 -0
  475. data/public/libs/codemirror/mode/smarty/index.html +83 -0
  476. data/public/libs/codemirror/mode/smarty/smarty.js +148 -0
  477. data/public/libs/codemirror/mode/sparql/index.html +42 -0
  478. data/public/libs/codemirror/mode/sparql/sparql.js +143 -0
  479. data/public/libs/codemirror/mode/sql/index.html +68 -0
  480. data/public/libs/codemirror/mode/sql/sql.js +268 -0
  481. data/public/libs/codemirror/mode/stex/index.html +98 -0
  482. data/public/libs/codemirror/mode/stex/stex.js +246 -0
  483. data/public/libs/codemirror/mode/stex/test.js +117 -0
  484. data/public/libs/codemirror/mode/tcl/index.html +129 -0
  485. data/public/libs/codemirror/mode/tcl/tcl.js +131 -0
  486. data/public/libs/codemirror/mode/tiddlywiki/index.html +142 -0
  487. data/public/libs/codemirror/mode/tiddlywiki/tiddlywiki.css +14 -0
  488. data/public/libs/codemirror/mode/tiddlywiki/tiddlywiki.js +353 -0
  489. data/public/libs/codemirror/mode/tiki/index.html +81 -0
  490. data/public/libs/codemirror/mode/tiki/tiki.css +26 -0
  491. data/public/libs/codemirror/mode/tiki/tiki.js +308 -0
  492. data/public/libs/codemirror/mode/turtle/index.html +39 -0
  493. data/public/libs/codemirror/mode/turtle/turtle.js +145 -0
  494. data/public/libs/codemirror/mode/vb/LICENSE.txt +21 -0
  495. data/public/libs/codemirror/mode/vb/index.html +88 -0
  496. data/public/libs/codemirror/mode/vb/vb.js +259 -0
  497. data/public/libs/codemirror/mode/vbscript/index.html +42 -0
  498. data/public/libs/codemirror/mode/vbscript/vbscript.js +26 -0
  499. data/public/libs/codemirror/mode/velocity/index.html +103 -0
  500. data/public/libs/codemirror/mode/velocity/velocity.js +144 -0
  501. data/public/libs/codemirror/mode/verilog/index.html +121 -0
  502. data/public/libs/codemirror/mode/verilog/verilog.js +182 -0
  503. data/public/libs/codemirror/mode/xml/index.html +45 -0
  504. data/public/libs/codemirror/mode/xml/xml.js +328 -0
  505. data/public/libs/codemirror/mode/xquery/LICENSE +20 -0
  506. data/public/libs/codemirror/mode/xquery/index.html +221 -0
  507. data/public/libs/codemirror/mode/xquery/test.js +64 -0
  508. data/public/libs/codemirror/mode/xquery/xquery.js +450 -0
  509. data/public/libs/codemirror/mode/yaml/index.html +68 -0
  510. data/public/libs/codemirror/mode/yaml/yaml.js +95 -0
  511. data/public/libs/codemirror/mode/z80/index.html +39 -0
  512. data/public/libs/codemirror/mode/z80/z80.js +85 -0
  513. data/public/libs/codemirror/package.json +21 -0
  514. data/public/libs/codemirror/test/doc_test.js +329 -0
  515. data/public/libs/codemirror/test/driver.js +138 -0
  516. data/public/libs/codemirror/test/index.html +182 -0
  517. data/public/libs/codemirror/test/lint/acorn.js +1593 -0
  518. data/public/libs/codemirror/test/lint/lint.js +112 -0
  519. data/public/libs/codemirror/test/lint/parse-js.js +1372 -0
  520. data/public/libs/codemirror/test/lint/walk.js +216 -0
  521. data/public/libs/codemirror/test/mode_test.css +10 -0
  522. data/public/libs/codemirror/test/mode_test.js +192 -0
  523. data/public/libs/codemirror/test/phantom_driver.js +31 -0
  524. data/public/libs/codemirror/test/run.js +33 -0
  525. data/public/libs/codemirror/test/test.js +1400 -0
  526. data/public/libs/codemirror/test/vim_test.js +1688 -0
  527. data/public/libs/codemirror/theme/ambiance-mobile.css +5 -0
  528. data/public/libs/codemirror/theme/ambiance.css +75 -0
  529. data/public/libs/codemirror/theme/blackboard.css +25 -0
  530. data/public/libs/codemirror/theme/cobalt.css +18 -0
  531. data/public/libs/codemirror/theme/eclipse.css +25 -0
  532. data/public/libs/codemirror/theme/elegant.css +10 -0
  533. data/public/libs/codemirror/theme/erlang-dark.css +21 -0
  534. data/public/libs/codemirror/theme/lesser-dark.css +44 -0
  535. data/public/libs/codemirror/theme/midnight.css +52 -0
  536. data/public/libs/codemirror/theme/monokai.css +28 -0
  537. data/public/libs/codemirror/theme/neat.css +9 -0
  538. data/public/libs/codemirror/theme/night.css +21 -0
  539. data/public/libs/codemirror/theme/rubyblue.css +21 -0
  540. data/public/libs/codemirror/theme/solarized.css +207 -0
  541. data/public/libs/codemirror/theme/twilight.css +26 -0
  542. data/public/libs/codemirror/theme/vibrant-ink.css +27 -0
  543. data/public/libs/codemirror/theme/xq-dark.css +46 -0
  544. data/public/libs/codemirror/theme/xq-light.css +43 -0
  545. data/public/libs/font-awesome/css/font-awesome-ie7.css +983 -0
  546. data/public/libs/font-awesome/css/font-awesome-ie7.min.css +24 -0
  547. data/public/libs/font-awesome/css/font-awesome.css +1268 -0
  548. data/public/libs/font-awesome/css/font-awesome.min.css +24 -0
  549. data/public/libs/font-awesome/font/FontAwesome.otf +0 -0
  550. data/public/libs/font-awesome/font/fontawesome-webfont.eot +0 -0
  551. data/public/libs/font-awesome/font/fontawesome-webfont.svg +339 -0
  552. data/public/libs/font-awesome/font/fontawesome-webfont.ttf +0 -0
  553. data/public/libs/font-awesome/font/fontawesome-webfont.woff +0 -0
  554. data/public/libs/font-awesome/less/bootstrap.less +78 -0
  555. data/public/libs/font-awesome/less/core.less +132 -0
  556. data/public/libs/font-awesome/less/extras.less +79 -0
  557. data/public/libs/font-awesome/less/font-awesome-ie7.less +413 -0
  558. data/public/libs/font-awesome/less/font-awesome.less +32 -0
  559. data/public/libs/font-awesome/less/icons.less +330 -0
  560. data/public/libs/font-awesome/less/mixins.less +34 -0
  561. data/public/libs/font-awesome/less/path.less +15 -0
  562. data/public/libs/font-awesome/less/variables.less +9 -0
  563. data/public/libs/jquery-1.10.0.min.js +6 -0
  564. data/public/libs/jquery-ui.min.js +12 -0
  565. data/public/libs/jquery.jsPlumb-1.4.0-all.js +9571 -0
  566. data/public/libs/jquery.livequery.js +226 -0
  567. data/public/libs/jsPlumbInitializer.js +72 -0
  568. data/public/libs/jstree/README.txt +10 -0
  569. data/public/libs/jstree/_demo/_dump.sql +20 -0
  570. data/public/libs/jstree/_demo/_inc/__mysql_errors.log +0 -0
  571. data/public/libs/jstree/_demo/_inc/class._database.php +146 -0
  572. data/public/libs/jstree/_demo/_inc/class._database_i.php +152 -0
  573. data/public/libs/jstree/_demo/_inc/class.tree.php +602 -0
  574. data/public/libs/jstree/_demo/_install.txt +6 -0
  575. data/public/libs/jstree/_demo/config.php +14 -0
  576. data/public/libs/jstree/_demo/file.png +0 -0
  577. data/public/libs/jstree/_demo/folder.png +0 -0
  578. data/public/libs/jstree/_demo/index.html +461 -0
  579. data/public/libs/jstree/_demo/root.png +0 -0
  580. data/public/libs/jstree/_demo/server.php +69 -0
  581. data/public/libs/jstree/_docs/!style.css +48 -0
  582. data/public/libs/jstree/_docs/_drive.png +0 -0
  583. data/public/libs/jstree/_docs/_html_data.html +2 -0
  584. data/public/libs/jstree/_docs/_json_data.json +4 -0
  585. data/public/libs/jstree/_docs/_search_data.json +6 -0
  586. data/public/libs/jstree/_docs/_search_result.json +1 -0
  587. data/public/libs/jstree/_docs/_xml_flat.xml +12 -0
  588. data/public/libs/jstree/_docs/_xml_nest.xml +18 -0
  589. data/public/libs/jstree/_docs/checkbox.html +171 -0
  590. data/public/libs/jstree/_docs/contextmenu.html +121 -0
  591. data/public/libs/jstree/_docs/cookies.html +97 -0
  592. data/public/libs/jstree/_docs/core.html +689 -0
  593. data/public/libs/jstree/_docs/crrm.html +316 -0
  594. data/public/libs/jstree/_docs/dnd.html +199 -0
  595. data/public/libs/jstree/_docs/hotkeys.html +82 -0
  596. data/public/libs/jstree/_docs/html_data.html +175 -0
  597. data/public/libs/jstree/_docs/index.html +86 -0
  598. data/public/libs/jstree/_docs/json_data.html +249 -0
  599. data/public/libs/jstree/_docs/languages.html +152 -0
  600. data/public/libs/jstree/_docs/logo.png +0 -0
  601. data/public/libs/jstree/_docs/search.html +153 -0
  602. data/public/libs/jstree/_docs/sort.html +85 -0
  603. data/public/libs/jstree/_docs/syntax/!script.js +2232 -0
  604. data/public/libs/jstree/_docs/syntax/!style.css +511 -0
  605. data/public/libs/jstree/_docs/syntax/clipboard.swf +0 -0
  606. data/public/libs/jstree/_docs/syntax/help.png +0 -0
  607. data/public/libs/jstree/_docs/syntax/magnifier.png +0 -0
  608. data/public/libs/jstree/_docs/syntax/page_white_code.png +0 -0
  609. data/public/libs/jstree/_docs/syntax/page_white_copy.png +0 -0
  610. data/public/libs/jstree/_docs/syntax/printer.png +0 -0
  611. data/public/libs/jstree/_docs/syntax/wrapping.png +0 -0
  612. data/public/libs/jstree/_docs/themeroller.html +107 -0
  613. data/public/libs/jstree/_docs/themes.html +127 -0
  614. data/public/libs/jstree/_docs/types.html +178 -0
  615. data/public/libs/jstree/_docs/ui.html +197 -0
  616. data/public/libs/jstree/_docs/unique.html +85 -0
  617. data/public/libs/jstree/_docs/xml_data.html +218 -0
  618. data/public/libs/jstree/_lib/jquery.cookie.js +96 -0
  619. data/public/libs/jstree/_lib/jquery.hotkeys.js +99 -0
  620. data/public/libs/jstree/_lib/jquery.js +5 -0
  621. data/public/libs/jstree/jquery.jstree.js +4564 -0
  622. data/public/libs/jstree/themes/apple/bg.jpg +0 -0
  623. data/public/libs/jstree/themes/apple/d.png +0 -0
  624. data/public/libs/jstree/themes/apple/dot_for_ie.gif +0 -0
  625. data/public/libs/jstree/themes/apple/style.css +61 -0
  626. data/public/libs/jstree/themes/apple/throbber.gif +0 -0
  627. data/public/libs/jstree/themes/classic/d.gif +0 -0
  628. data/public/libs/jstree/themes/classic/d.png +0 -0
  629. data/public/libs/jstree/themes/classic/dot_for_ie.gif +0 -0
  630. data/public/libs/jstree/themes/classic/style.css +77 -0
  631. data/public/libs/jstree/themes/classic/throbber.gif +0 -0
  632. data/public/libs/jstree/themes/default-rtl/d.gif +0 -0
  633. data/public/libs/jstree/themes/default-rtl/d.png +0 -0
  634. data/public/libs/jstree/themes/default-rtl/dots.gif +0 -0
  635. data/public/libs/jstree/themes/default-rtl/style.css +84 -0
  636. data/public/libs/jstree/themes/default-rtl/throbber.gif +0 -0
  637. data/public/libs/jstree/themes/default/d.gif +0 -0
  638. data/public/libs/jstree/themes/default/d.png +0 -0
  639. data/public/libs/jstree/themes/default/style.css +74 -0
  640. data/public/libs/jstree/themes/default/throbber.gif +0 -0
  641. data/public/themes/geo-bootstrap/README.md +25 -0
  642. data/public/themes/geo-bootstrap/img/flames.gif +0 -0
  643. data/public/themes/geo-bootstrap/img/glyphicons-halflings-white.png +0 -0
  644. data/public/themes/geo-bootstrap/img/glyphicons-halflings.png +0 -0
  645. data/public/themes/geo-bootstrap/img/microfab.gif +0 -0
  646. data/public/themes/geo-bootstrap/img/progress.gif +0 -0
  647. data/public/themes/geo-bootstrap/img/rainbow.gif +0 -0
  648. data/public/themes/geo-bootstrap/img/stars.gif +0 -0
  649. data/public/themes/geo-bootstrap/img/test/7upspot.gif +0 -0
  650. data/public/themes/geo-bootstrap/img/test/americanflag.gif +0 -0
  651. data/public/themes/geo-bootstrap/img/test/community.gif +0 -0
  652. data/public/themes/geo-bootstrap/img/test/computer-01.gif +0 -0
  653. data/public/themes/geo-bootstrap/img/test/computer.gif +0 -0
  654. data/public/themes/geo-bootstrap/img/test/construction.gif +0 -0
  655. data/public/themes/geo-bootstrap/img/test/counter.gif +0 -0
  656. data/public/themes/geo-bootstrap/img/test/counter2.gif +0 -0
  657. data/public/themes/geo-bootstrap/img/test/divider.gif +0 -0
  658. data/public/themes/geo-bootstrap/img/test/divider1.gif +0 -0
  659. data/public/themes/geo-bootstrap/img/test/divider2.gif +0 -0
  660. data/public/themes/geo-bootstrap/img/test/divider3.gif +0 -0
  661. data/public/themes/geo-bootstrap/img/test/divider4.gif +0 -0
  662. data/public/themes/geo-bootstrap/img/test/drudgesiren.gif +0 -0
  663. data/public/themes/geo-bootstrap/img/test/emailme.gif +0 -0
  664. data/public/themes/geo-bootstrap/img/test/funky.gif +0 -0
  665. data/public/themes/geo-bootstrap/img/test/geocities.jpg +0 -0
  666. data/public/themes/geo-bootstrap/img/test/hacker.gif +0 -0
  667. data/public/themes/geo-bootstrap/img/test/heart.gif +0 -0
  668. data/public/themes/geo-bootstrap/img/test/hot.gif +0 -0
  669. data/public/themes/geo-bootstrap/img/test/ie_logo.gif +0 -0
  670. data/public/themes/geo-bootstrap/img/test/mailkitten.gif +0 -0
  671. data/public/themes/geo-bootstrap/img/test/mchammer.gif +0 -0
  672. data/public/themes/geo-bootstrap/img/test/new.gif +0 -0
  673. data/public/themes/geo-bootstrap/img/test/new2.gif +0 -0
  674. data/public/themes/geo-bootstrap/img/test/noframes.gif +0 -0
  675. data/public/themes/geo-bootstrap/img/test/notepad.gif +0 -0
  676. data/public/themes/geo-bootstrap/img/test/ns_logo.gif +0 -0
  677. data/public/themes/geo-bootstrap/img/test/sign-in.gif +0 -0
  678. data/public/themes/geo-bootstrap/img/test/spinningearth.gif +0 -0
  679. data/public/themes/geo-bootstrap/img/test/underconstruction.gif +0 -0
  680. data/public/themes/geo-bootstrap/img/test/wabwalk.gif +0 -0
  681. data/public/themes/geo-bootstrap/img/test/webtrips.gif +0 -0
  682. data/public/themes/geo-bootstrap/img/test/yahooweek.gif +0 -0
  683. data/public/themes/geo-bootstrap/package.json +21 -0
  684. data/public/themes/geo-bootstrap/swatch/bootstrap-responsive.css +1109 -0
  685. data/public/themes/geo-bootstrap/swatch/bootstrap-responsive.min.css +9 -0
  686. data/public/themes/geo-bootstrap/swatch/bootstrap.css +6462 -0
  687. data/public/themes/geo-bootstrap/swatch/bootstrap.min.css +9 -0
  688. metadata +791 -0
@@ -0,0 +1,30 @@
1
+ // TODO number prefixes
2
+ (function() {
3
+ // Really primitive kill-ring implementation.
4
+ var killRing = [];
5
+ function addToRing(str) {
6
+ killRing.push(str);
7
+ if (killRing.length > 50) killRing.shift();
8
+ }
9
+ function getFromRing() { return killRing[killRing.length - 1] || ""; }
10
+ function popFromRing() { if (killRing.length > 1) killRing.pop(); return getFromRing(); }
11
+
12
+ CodeMirror.keyMap.emacs = {
13
+ "Ctrl-X": function(cm) {cm.setOption("keyMap", "emacs-Ctrl-X");},
14
+ "Ctrl-W": function(cm) {addToRing(cm.getSelection()); cm.replaceSelection("");},
15
+ "Ctrl-Alt-W": function(cm) {addToRing(cm.getSelection()); cm.replaceSelection("");},
16
+ "Alt-W": function(cm) {addToRing(cm.getSelection());},
17
+ "Ctrl-Y": function(cm) {cm.replaceSelection(getFromRing());},
18
+ "Alt-Y": function(cm) {cm.replaceSelection(popFromRing());},
19
+ "Ctrl-/": "undo", "Shift-Ctrl--": "undo", "Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd",
20
+ "Ctrl-S": "findNext", "Ctrl-R": "findPrev", "Ctrl-G": "clearSearch", "Shift-Alt-5": "replace",
21
+ "Ctrl-Z": "undo", "Cmd-Z": "undo", "Alt-/": "autocomplete", "Alt-V": "goPageUp",
22
+ "Ctrl-J": "newlineAndIndent", "Enter": false, "Tab": "indentAuto",
23
+ fallthrough: ["basic", "emacsy"]
24
+ };
25
+
26
+ CodeMirror.keyMap["emacs-Ctrl-X"] = {
27
+ "Ctrl-S": "save", "Ctrl-W": "save", "S": "saveAll", "F": "open", "U": "undo", "K": "close",
28
+ auto: "emacs", nofallthrough: true
29
+ };
30
+ })();
@@ -0,0 +1,3044 @@
1
+ /**
2
+ * Supported keybindings:
3
+ *
4
+ * Motion:
5
+ * h, j, k, l
6
+ * gj, gk
7
+ * e, E, w, W, b, B, ge, gE
8
+ * f<character>, F<character>, t<character>, T<character>
9
+ * $, ^, 0, -, +, _
10
+ * gg, G
11
+ * %
12
+ * '<character>, `<character>
13
+ *
14
+ * Operator:
15
+ * d, y, c
16
+ * dd, yy, cc
17
+ * g~, g~g~
18
+ * >, <, >>, <<
19
+ *
20
+ * Operator-Motion:
21
+ * x, X, D, Y, C, ~
22
+ *
23
+ * Action:
24
+ * a, i, s, A, I, S, o, O
25
+ * zz, z., z<CR>, zt, zb, z-
26
+ * J
27
+ * u, Ctrl-r
28
+ * m<character>
29
+ * r<character>
30
+ *
31
+ * Modes:
32
+ * ESC - leave insert mode, visual mode, and clear input state.
33
+ * Ctrl-[, Ctrl-c - same as ESC.
34
+ *
35
+ * Registers: unamed, -, a-z, A-Z, 0-9
36
+ * (Does not respect the special case for number registers when delete
37
+ * operator is made with these commands: %, (, ), , /, ?, n, N, {, } )
38
+ * TODO: Implement the remaining registers.
39
+ * Marks: a-z, A-Z, and 0-9
40
+ * TODO: Implement the remaining special marks. They have more complex
41
+ * behavior.
42
+ *
43
+ * Code structure:
44
+ * 1. Default keymap
45
+ * 2. Variable declarations and short basic helpers
46
+ * 3. Instance (External API) implementation
47
+ * 4. Internal state tracking objects (input state, counter) implementation
48
+ * and instanstiation
49
+ * 5. Key handler (the main command dispatcher) implementation
50
+ * 6. Motion, operator, and action implementations
51
+ * 7. Helper functions for the key handler, motions, operators, and actions
52
+ * 8. Set up Vim to work as a keymap for CodeMirror.
53
+ */
54
+
55
+ (function() {
56
+ 'use strict';
57
+
58
+ var defaultKeymap = [
59
+ // Key to key mapping. This goes first to make it possible to override
60
+ // existing mappings.
61
+ { keys: ['Left'], type: 'keyToKey', toKeys: ['h'] },
62
+ { keys: ['Right'], type: 'keyToKey', toKeys: ['l'] },
63
+ { keys: ['Up'], type: 'keyToKey', toKeys: ['k'] },
64
+ { keys: ['Down'], type: 'keyToKey', toKeys: ['j'] },
65
+ { keys: ['Space'], type: 'keyToKey', toKeys: ['l'] },
66
+ { keys: ['Backspace'], type: 'keyToKey', toKeys: ['h'] },
67
+ { keys: ['Ctrl-Space'], type: 'keyToKey', toKeys: ['W'] },
68
+ { keys: ['Ctrl-Backspace'], type: 'keyToKey', toKeys: ['B'] },
69
+ { keys: ['Shift-Space'], type: 'keyToKey', toKeys: ['w'] },
70
+ { keys: ['Shift-Backspace'], type: 'keyToKey', toKeys: ['b'] },
71
+ { keys: ['Ctrl-n'], type: 'keyToKey', toKeys: ['j'] },
72
+ { keys: ['Ctrl-p'], type: 'keyToKey', toKeys: ['k'] },
73
+ { keys: ['Ctrl-['], type: 'keyToKey', toKeys: ['Esc'] },
74
+ { keys: ['Ctrl-c'], type: 'keyToKey', toKeys: ['Esc'] },
75
+ { keys: ['s'], type: 'keyToKey', toKeys: ['c', 'l'] },
76
+ { keys: ['S'], type: 'keyToKey', toKeys: ['c', 'c'] },
77
+ { keys: ['Home'], type: 'keyToKey', toKeys: ['0'] },
78
+ { keys: ['End'], type: 'keyToKey', toKeys: ['$'] },
79
+ { keys: ['PageUp'], type: 'keyToKey', toKeys: ['Ctrl-b'] },
80
+ { keys: ['PageDown'], type: 'keyToKey', toKeys: ['Ctrl-f'] },
81
+ // Motions
82
+ { keys: ['H'], type: 'motion',
83
+ motion: 'moveToTopLine',
84
+ motionArgs: { linewise: true }},
85
+ { keys: ['M'], type: 'motion',
86
+ motion: 'moveToMiddleLine',
87
+ motionArgs: { linewise: true }},
88
+ { keys: ['L'], type: 'motion',
89
+ motion: 'moveToBottomLine',
90
+ motionArgs: { linewise: true }},
91
+ { keys: ['h'], type: 'motion',
92
+ motion: 'moveByCharacters',
93
+ motionArgs: { forward: false }},
94
+ { keys: ['l'], type: 'motion',
95
+ motion: 'moveByCharacters',
96
+ motionArgs: { forward: true }},
97
+ { keys: ['j'], type: 'motion',
98
+ motion: 'moveByLines',
99
+ motionArgs: { forward: true, linewise: true }},
100
+ { keys: ['k'], type: 'motion',
101
+ motion: 'moveByLines',
102
+ motionArgs: { forward: false, linewise: true }},
103
+ { keys: ['g','j'], type: 'motion',
104
+ motion: 'moveByDisplayLines',
105
+ motionArgs: { forward: true }},
106
+ { keys: ['g','k'], type: 'motion',
107
+ motion: 'moveByDisplayLines',
108
+ motionArgs: { forward: false }},
109
+ { keys: ['w'], type: 'motion',
110
+ motion: 'moveByWords',
111
+ motionArgs: { forward: true, wordEnd: false }},
112
+ { keys: ['W'], type: 'motion',
113
+ motion: 'moveByWords',
114
+ motionArgs: { forward: true, wordEnd: false, bigWord: true }},
115
+ { keys: ['e'], type: 'motion',
116
+ motion: 'moveByWords',
117
+ motionArgs: { forward: true, wordEnd: true, inclusive: true }},
118
+ { keys: ['E'], type: 'motion',
119
+ motion: 'moveByWords',
120
+ motionArgs: { forward: true, wordEnd: true, bigWord: true,
121
+ inclusive: true }},
122
+ { keys: ['b'], type: 'motion',
123
+ motion: 'moveByWords',
124
+ motionArgs: { forward: false, wordEnd: false }},
125
+ { keys: ['B'], type: 'motion',
126
+ motion: 'moveByWords',
127
+ motionArgs: { forward: false, wordEnd: false, bigWord: true }},
128
+ { keys: ['g', 'e'], type: 'motion',
129
+ motion: 'moveByWords',
130
+ motionArgs: { forward: false, wordEnd: true, inclusive: true }},
131
+ { keys: ['g', 'E'], type: 'motion',
132
+ motion: 'moveByWords',
133
+ motionArgs: { forward: false, wordEnd: true, bigWord: true,
134
+ inclusive: true }},
135
+ { keys: ['{'], type: 'motion', motion: 'moveByParagraph',
136
+ motionArgs: { forward: false }},
137
+ { keys: ['}'], type: 'motion', motion: 'moveByParagraph',
138
+ motionArgs: { forward: true }},
139
+ { keys: ['Ctrl-f'], type: 'motion',
140
+ motion: 'moveByPage', motionArgs: { forward: true }},
141
+ { keys: ['Ctrl-b'], type: 'motion',
142
+ motion: 'moveByPage', motionArgs: { forward: false }},
143
+ { keys: ['Ctrl-d'], type: 'motion',
144
+ motion: 'moveByScroll',
145
+ motionArgs: { forward: true, explicitRepeat: true }},
146
+ { keys: ['Ctrl-u'], type: 'motion',
147
+ motion: 'moveByScroll',
148
+ motionArgs: { forward: false, explicitRepeat: true }},
149
+ { keys: ['g', 'g'], type: 'motion',
150
+ motion: 'moveToLineOrEdgeOfDocument',
151
+ motionArgs: { forward: false, explicitRepeat: true, linewise: true }},
152
+ { keys: ['G'], type: 'motion',
153
+ motion: 'moveToLineOrEdgeOfDocument',
154
+ motionArgs: { forward: true, explicitRepeat: true, linewise: true }},
155
+ { keys: ['0'], type: 'motion', motion: 'moveToStartOfLine' },
156
+ { keys: ['^'], type: 'motion',
157
+ motion: 'moveToFirstNonWhiteSpaceCharacter' },
158
+ { keys: ['+'], type: 'motion',
159
+ motion: 'moveByLines',
160
+ motionArgs: { forward: true, toFirstChar:true }},
161
+ { keys: ['-'], type: 'motion',
162
+ motion: 'moveByLines',
163
+ motionArgs: { forward: false, toFirstChar:true }},
164
+ { keys: ['_'], type: 'motion',
165
+ motion: 'moveByLines',
166
+ motionArgs: { forward: true, toFirstChar:true, repeatOffset:-1 }},
167
+ { keys: ['$'], type: 'motion',
168
+ motion: 'moveToEol',
169
+ motionArgs: { inclusive: true }},
170
+ { keys: ['%'], type: 'motion',
171
+ motion: 'moveToMatchedSymbol',
172
+ motionArgs: { inclusive: true }},
173
+ { keys: ['f', 'character'], type: 'motion',
174
+ motion: 'moveToCharacter',
175
+ motionArgs: { forward: true , inclusive: true }},
176
+ { keys: ['F', 'character'], type: 'motion',
177
+ motion: 'moveToCharacter',
178
+ motionArgs: { forward: false }},
179
+ { keys: ['t', 'character'], type: 'motion',
180
+ motion: 'moveTillCharacter',
181
+ motionArgs: { forward: true, inclusive: true }},
182
+ { keys: ['T', 'character'], type: 'motion',
183
+ motion: 'moveTillCharacter',
184
+ motionArgs: { forward: false }},
185
+ { keys: [';'], type: 'motion', motion: 'repeatLastCharacterSearch',
186
+ motionArgs: { forward: true }},
187
+ { keys: [','], type: 'motion', motion: 'repeatLastCharacterSearch',
188
+ motionArgs: { forward: false }},
189
+ { keys: ['\'', 'character'], type: 'motion', motion: 'goToMark' },
190
+ { keys: ['`', 'character'], type: 'motion', motion: 'goToMark' },
191
+ { keys: [']', '`',], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } },
192
+ { keys: ['[', '`',], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } },
193
+ { keys: [']', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } },
194
+ { keys: ['[', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } },
195
+ { keys: [']', 'character'], type: 'motion',
196
+ motion: 'moveToSymbol',
197
+ motionArgs: { forward: true}},
198
+ { keys: ['[', 'character'], type: 'motion',
199
+ motion: 'moveToSymbol',
200
+ motionArgs: { forward: false}},
201
+ { keys: ['|'], type: 'motion',
202
+ motion: 'moveToColumn',
203
+ motionArgs: { }},
204
+ // Operators
205
+ { keys: ['d'], type: 'operator', operator: 'delete' },
206
+ { keys: ['y'], type: 'operator', operator: 'yank' },
207
+ { keys: ['c'], type: 'operator', operator: 'change',
208
+ operatorArgs: { enterInsertMode: true } },
209
+ { keys: ['>'], type: 'operator', operator: 'indent',
210
+ operatorArgs: { indentRight: true }},
211
+ { keys: ['<'], type: 'operator', operator: 'indent',
212
+ operatorArgs: { indentRight: false }},
213
+ { keys: ['g', '~'], type: 'operator', operator: 'swapcase' },
214
+ { keys: ['n'], type: 'motion', motion: 'findNext',
215
+ motionArgs: { forward: true }},
216
+ { keys: ['N'], type: 'motion', motion: 'findNext',
217
+ motionArgs: { forward: false }},
218
+ // Operator-Motion dual commands
219
+ { keys: ['x'], type: 'operatorMotion', operator: 'delete',
220
+ motion: 'moveByCharacters', motionArgs: { forward: true },
221
+ operatorMotionArgs: { visualLine: false }},
222
+ { keys: ['X'], type: 'operatorMotion', operator: 'delete',
223
+ motion: 'moveByCharacters', motionArgs: { forward: false },
224
+ operatorMotionArgs: { visualLine: true }},
225
+ { keys: ['D'], type: 'operatorMotion', operator: 'delete',
226
+ motion: 'moveToEol', motionArgs: { inclusive: true },
227
+ operatorMotionArgs: { visualLine: true }},
228
+ { keys: ['Y'], type: 'operatorMotion', operator: 'yank',
229
+ motion: 'moveToEol', motionArgs: { inclusive: true },
230
+ operatorMotionArgs: { visualLine: true }},
231
+ { keys: ['C'], type: 'operatorMotion',
232
+ operator: 'change', operatorArgs: { enterInsertMode: true },
233
+ motion: 'moveToEol', motionArgs: { inclusive: true },
234
+ operatorMotionArgs: { visualLine: true }},
235
+ { keys: ['~'], type: 'operatorMotion', operator: 'swapcase',
236
+ motion: 'moveByCharacters', motionArgs: { forward: true }},
237
+ // Actions
238
+ { keys: ['a'], type: 'action', action: 'enterInsertMode',
239
+ actionArgs: { insertAt: 'charAfter' }},
240
+ { keys: ['A'], type: 'action', action: 'enterInsertMode',
241
+ actionArgs: { insertAt: 'eol' }},
242
+ { keys: ['i'], type: 'action', action: 'enterInsertMode' },
243
+ { keys: ['I'], type: 'action', action: 'enterInsertMode',
244
+ motion: 'moveToFirstNonWhiteSpaceCharacter' },
245
+ { keys: ['o'], type: 'action', action: 'newLineAndEnterInsertMode',
246
+ actionArgs: { after: true }},
247
+ { keys: ['O'], type: 'action', action: 'newLineAndEnterInsertMode',
248
+ actionArgs: { after: false }},
249
+ { keys: ['v'], type: 'action', action: 'toggleVisualMode' },
250
+ { keys: ['V'], type: 'action', action: 'toggleVisualMode',
251
+ actionArgs: { linewise: true }},
252
+ { keys: ['J'], type: 'action', action: 'joinLines' },
253
+ { keys: ['p'], type: 'action', action: 'paste',
254
+ actionArgs: { after: true }},
255
+ { keys: ['P'], type: 'action', action: 'paste',
256
+ actionArgs: { after: false }},
257
+ { keys: ['r', 'character'], type: 'action', action: 'replace' },
258
+ { keys: ['u'], type: 'action', action: 'undo' },
259
+ { keys: ['Ctrl-r'], type: 'action', action: 'redo' },
260
+ { keys: ['m', 'character'], type: 'action', action: 'setMark' },
261
+ { keys: ['\"', 'character'], type: 'action', action: 'setRegister' },
262
+ { keys: ['z', 'z'], type: 'action', action: 'scrollToCursor',
263
+ actionArgs: { position: 'center' }},
264
+ { keys: ['z', '.'], type: 'action', action: 'scrollToCursor',
265
+ actionArgs: { position: 'center' },
266
+ motion: 'moveToFirstNonWhiteSpaceCharacter' },
267
+ { keys: ['z', 't'], type: 'action', action: 'scrollToCursor',
268
+ actionArgs: { position: 'top' }},
269
+ { keys: ['z', 'Enter'], type: 'action', action: 'scrollToCursor',
270
+ actionArgs: { position: 'top' },
271
+ motion: 'moveToFirstNonWhiteSpaceCharacter' },
272
+ { keys: ['z', '-'], type: 'action', action: 'scrollToCursor',
273
+ actionArgs: { position: 'bottom' }},
274
+ { keys: ['z', 'b'], type: 'action', action: 'scrollToCursor',
275
+ actionArgs: { position: 'bottom' },
276
+ motion: 'moveToFirstNonWhiteSpaceCharacter' },
277
+ { keys: ['.'], type: 'action', action: 'repeatLastEdit' },
278
+ { keys: ['Ctrl-a'], type: 'action', action: 'incrementNumberToken',
279
+ actionArgs: {increase: true, backtrack: false}},
280
+ { keys: ['Ctrl-x'], type: 'action', action: 'incrementNumberToken',
281
+ actionArgs: {increase: false, backtrack: false}},
282
+ // Text object motions
283
+ { keys: ['a', 'character'], type: 'motion',
284
+ motion: 'textObjectManipulation' },
285
+ { keys: ['i', 'character'], type: 'motion',
286
+ motion: 'textObjectManipulation',
287
+ motionArgs: { textObjectInner: true }},
288
+ // Search
289
+ { keys: ['/'], type: 'search',
290
+ searchArgs: { forward: true, querySrc: 'prompt' }},
291
+ { keys: ['?'], type: 'search',
292
+ searchArgs: { forward: false, querySrc: 'prompt' }},
293
+ { keys: ['*'], type: 'search',
294
+ searchArgs: { forward: true, querySrc: 'wordUnderCursor' }},
295
+ { keys: ['#'], type: 'search',
296
+ searchArgs: { forward: false, querySrc: 'wordUnderCursor' }},
297
+ // Ex command
298
+ { keys: [':'], type: 'ex' }
299
+ ];
300
+
301
+ var Vim = function() {
302
+ var alphabetRegex = /[A-Za-z]/;
303
+ var numberRegex = /[\d]/;
304
+ var whiteSpaceRegex = /\s/;
305
+ var wordRegexp = [(/\w/), (/[^\w\s]/)], bigWordRegexp = [(/\S/)];
306
+ function makeKeyRange(start, size) {
307
+ var keys = [];
308
+ for (var i = start; i < start + size; i++) {
309
+ keys.push(String.fromCharCode(i));
310
+ }
311
+ return keys;
312
+ }
313
+ var upperCaseAlphabet = makeKeyRange(65, 26);
314
+ var lowerCaseAlphabet = makeKeyRange(97, 26);
315
+ var numbers = makeKeyRange(48, 10);
316
+ var SPECIAL_SYMBOLS = '~`!@#$%^&*()_-+=[{}]\\|/?.,<>:;\"\'';
317
+ var specialSymbols = SPECIAL_SYMBOLS.split('');
318
+ var specialKeys = ['Left', 'Right', 'Up', 'Down', 'Space', 'Backspace',
319
+ 'Esc', 'Home', 'End', 'PageUp', 'PageDown', 'Enter'];
320
+ var validMarks = upperCaseAlphabet.concat(lowerCaseAlphabet).concat(
321
+ numbers).concat(['<', '>']);
322
+ var validRegisters = upperCaseAlphabet.concat(lowerCaseAlphabet).concat(
323
+ numbers).concat('-\"'.split(''));
324
+
325
+ function isAlphabet(k) {
326
+ return alphabetRegex.test(k);
327
+ }
328
+ function isLine(cm, line) {
329
+ return line >= cm.firstLine() && line <= cm.lastLine();
330
+ }
331
+ function isLowerCase(k) {
332
+ return (/^[a-z]$/).test(k);
333
+ }
334
+ function isMatchableSymbol(k) {
335
+ return '()[]{}'.indexOf(k) != -1;
336
+ }
337
+ function isNumber(k) {
338
+ return numberRegex.test(k);
339
+ }
340
+ function isUpperCase(k) {
341
+ return (/^[A-Z]$/).test(k);
342
+ }
343
+ function isAlphanumeric(k) {
344
+ return (/^[\w]$/).test(k);
345
+ }
346
+ function isWhiteSpace(k) {
347
+ return whiteSpaceRegex.test(k);
348
+ }
349
+ function isWhiteSpaceString(k) {
350
+ return (/^\s*$/).test(k);
351
+ }
352
+ function inRangeInclusive(x, start, end) {
353
+ return x >= start && x <= end;
354
+ }
355
+ function inArray(val, arr) {
356
+ for (var i = 0; i < arr.length; i++) {
357
+ if (arr[i] == val) {
358
+ return true;
359
+ }
360
+ }
361
+ return false;
362
+ }
363
+
364
+ // Global Vim state. Call getVimGlobalState to get and initialize.
365
+ var vimGlobalState;
366
+ function getVimGlobalState() {
367
+ if (!vimGlobalState) {
368
+ vimGlobalState = {
369
+ // The current search query.
370
+ searchQuery: null,
371
+ // Whether we are searching backwards.
372
+ searchIsReversed: false,
373
+ // Recording latest f, t, F or T motion command.
374
+ lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''},
375
+ registerController: new RegisterController({})
376
+ };
377
+ }
378
+ return vimGlobalState;
379
+ }
380
+ function getVimState(cm) {
381
+ if (!cm.vimState) {
382
+ // Store instance state in the CodeMirror object.
383
+ cm.vimState = {
384
+ inputState: new InputState(),
385
+ // When using jk for navigation, if you move from a longer line to a
386
+ // shorter line, the cursor may clip to the end of the shorter line.
387
+ // If j is pressed again and cursor goes to the next line, the
388
+ // cursor should go back to its horizontal position on the longer
389
+ // line if it can. This is to keep track of the horizontal position.
390
+ lastHPos: -1,
391
+ // Doing the same with screen-position for gj/gk
392
+ lastHSPos: -1,
393
+ // The last motion command run. Cleared if a non-motion command gets
394
+ // executed in between.
395
+ lastMotion: null,
396
+ marks: {},
397
+ visualMode: false,
398
+ // If we are in visual line mode. No effect if visualMode is false.
399
+ visualLine: false
400
+ };
401
+ }
402
+ return cm.vimState;
403
+ }
404
+
405
+ var vimApi= {
406
+ buildKeyMap: function() {
407
+ // TODO: Convert keymap into dictionary format for fast lookup.
408
+ },
409
+ // Testing hook, though it might be useful to expose the register
410
+ // controller anyways.
411
+ getRegisterController: function() {
412
+ return getVimGlobalState().registerController;
413
+ },
414
+ // Testing hook.
415
+ clearVimGlobalState_: function() {
416
+ vimGlobalState = null;
417
+ },
418
+ map: function(lhs, rhs) {
419
+ // Add user defined key bindings.
420
+ exCommandDispatcher.map(lhs, rhs);
421
+ },
422
+ defineEx: function(name, prefix, func){
423
+ if (name.indexOf(prefix) === 0) {
424
+ exCommands[name]=func;
425
+ exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'};
426
+ }else throw new Error("(Vim.defineEx) \""+prefix+"\" is not a prefix of \""+name+"\", command not registered");
427
+ },
428
+ // Initializes vim state variable on the CodeMirror object. Should only be
429
+ // called lazily by handleKey or for testing.
430
+ maybeInitState: function(cm) {
431
+ getVimState(cm);
432
+ },
433
+ // This is the outermost function called by CodeMirror, after keys have
434
+ // been mapped to their Vim equivalents.
435
+ handleKey: function(cm, key) {
436
+ var command;
437
+ var vim = getVimState(cm);
438
+ if (key == 'Esc') {
439
+ // Clear input state and get back to normal mode.
440
+ vim.inputState = new InputState();
441
+ if (vim.visualMode) {
442
+ exitVisualMode(cm, vim);
443
+ }
444
+ return;
445
+ }
446
+ if (vim.visualMode &&
447
+ cursorEqual(cm.getCursor('head'), cm.getCursor('anchor'))) {
448
+ // The selection was cleared. Exit visual mode.
449
+ exitVisualMode(cm, vim);
450
+ }
451
+ if (!vim.visualMode &&
452
+ !cursorEqual(cm.getCursor('head'), cm.getCursor('anchor'))) {
453
+ vim.visualMode = true;
454
+ vim.visualLine = false;
455
+ }
456
+ if (key != '0' || (key == '0' && vim.inputState.getRepeat() === 0)) {
457
+ // Have to special case 0 since it's both a motion and a number.
458
+ command = commandDispatcher.matchCommand(key, defaultKeymap, vim);
459
+ }
460
+ if (!command) {
461
+ if (isNumber(key)) {
462
+ // Increment count unless count is 0 and key is 0.
463
+ vim.inputState.pushRepeatDigit(key);
464
+ }
465
+ return;
466
+ }
467
+ if (command.type == 'keyToKey') {
468
+ // TODO: prevent infinite recursion.
469
+ for (var i = 0; i < command.toKeys.length; i++) {
470
+ this.handleKey(cm, command.toKeys[i]);
471
+ }
472
+ } else {
473
+ commandDispatcher.processCommand(cm, vim, command);
474
+ }
475
+ }
476
+ };
477
+
478
+ // Represents the current input state.
479
+ function InputState() {
480
+ this.prefixRepeat = [];
481
+ this.motionRepeat = [];
482
+
483
+ this.operator = null;
484
+ this.operatorArgs = null;
485
+ this.motion = null;
486
+ this.motionArgs = null;
487
+ this.keyBuffer = []; // For matching multi-key commands.
488
+ this.registerName = null; // Defaults to the unamed register.
489
+ }
490
+ InputState.prototype.pushRepeatDigit = function(n) {
491
+ if (!this.operator) {
492
+ this.prefixRepeat = this.prefixRepeat.concat(n);
493
+ } else {
494
+ this.motionRepeat = this.motionRepeat.concat(n);
495
+ }
496
+ };
497
+ InputState.prototype.getRepeat = function() {
498
+ var repeat = 0;
499
+ if (this.prefixRepeat.length > 0 || this.motionRepeat.length > 0) {
500
+ repeat = 1;
501
+ if (this.prefixRepeat.length > 0) {
502
+ repeat *= parseInt(this.prefixRepeat.join(''), 10);
503
+ }
504
+ if (this.motionRepeat.length > 0) {
505
+ repeat *= parseInt(this.motionRepeat.join(''), 10);
506
+ }
507
+ }
508
+ return repeat;
509
+ };
510
+
511
+ /*
512
+ * Register stores information about copy and paste registers. Besides
513
+ * text, a register must store whether it is linewise (i.e., when it is
514
+ * pasted, should it insert itself into a new line, or should the text be
515
+ * inserted at the cursor position.)
516
+ */
517
+ function Register(text, linewise) {
518
+ this.clear();
519
+ if (text) {
520
+ this.set(text, linewise);
521
+ }
522
+ }
523
+ Register.prototype = {
524
+ set: function(text, linewise) {
525
+ this.text = text;
526
+ this.linewise = !!linewise;
527
+ },
528
+ append: function(text, linewise) {
529
+ // if this register has ever been set to linewise, use linewise.
530
+ if (linewise || this.linewise) {
531
+ this.text += '\n' + text;
532
+ this.linewise = true;
533
+ } else {
534
+ this.text += text;
535
+ }
536
+ },
537
+ clear: function() {
538
+ this.text = '';
539
+ this.linewise = false;
540
+ },
541
+ toString: function() { return this.text; }
542
+ };
543
+
544
+ /*
545
+ * vim registers allow you to keep many independent copy and paste buffers.
546
+ * See http://usevim.com/2012/04/13/registers/ for an introduction.
547
+ *
548
+ * RegisterController keeps the state of all the registers. An initial
549
+ * state may be passed in. The unnamed register '"' will always be
550
+ * overridden.
551
+ */
552
+ function RegisterController(registers) {
553
+ this.registers = registers;
554
+ this.unamedRegister = registers['\"'] = new Register();
555
+ }
556
+ RegisterController.prototype = {
557
+ pushText: function(registerName, operator, text, linewise) {
558
+ // Lowercase and uppercase registers refer to the same register.
559
+ // Uppercase just means append.
560
+ var register = this.isValidRegister(registerName) ?
561
+ this.getRegister(registerName) : null;
562
+ // if no register/an invalid register was specified, things go to the
563
+ // default registers
564
+ if (!register) {
565
+ switch (operator) {
566
+ case 'yank':
567
+ // The 0 register contains the text from the most recent yank.
568
+ this.registers['0'] = new Register(text, linewise);
569
+ break;
570
+ case 'delete':
571
+ case 'change':
572
+ if (text.indexOf('\n') == -1) {
573
+ // Delete less than 1 line. Update the small delete register.
574
+ this.registers['-'] = new Register(text, linewise);
575
+ } else {
576
+ // Shift down the contents of the numbered registers and put the
577
+ // deleted text into register 1.
578
+ this.shiftNumericRegisters_();
579
+ this.registers['1'] = new Register(text, linewise);
580
+ }
581
+ break;
582
+ }
583
+ // Make sure the unnamed register is set to what just happened
584
+ this.unamedRegister.set(text, linewise);
585
+ return;
586
+ }
587
+
588
+ // If we've gotten to this point, we've actually specified a register
589
+ var append = isUpperCase(registerName);
590
+ if (append) {
591
+ register.append(text, linewise);
592
+ // The unamed register always has the same value as the last used
593
+ // register.
594
+ this.unamedRegister.append(text, linewise);
595
+ } else {
596
+ register.set(text, linewise);
597
+ this.unamedRegister.set(text, linewise);
598
+ }
599
+ },
600
+ // Gets the register named @name. If one of @name doesn't already exist,
601
+ // create it. If @name is invalid, return the unamedRegister.
602
+ getRegister: function(name) {
603
+ if (!this.isValidRegister(name)) {
604
+ return this.unamedRegister;
605
+ }
606
+ name = name.toLowerCase();
607
+ if (!this.registers[name]) {
608
+ this.registers[name] = new Register();
609
+ }
610
+ return this.registers[name];
611
+ },
612
+ isValidRegister: function(name) {
613
+ return name && inArray(name, validRegisters);
614
+ },
615
+ shiftNumericRegisters_: function() {
616
+ for (var i = 9; i >= 2; i--) {
617
+ this.registers[i] = this.getRegister('' + (i - 1));
618
+ }
619
+ }
620
+ };
621
+
622
+ var commandDispatcher = {
623
+ matchCommand: function(key, keyMap, vim) {
624
+ var inputState = vim.inputState;
625
+ var keys = inputState.keyBuffer.concat(key);
626
+ for (var i = 0; i < keyMap.length; i++) {
627
+ var command = keyMap[i];
628
+ if (matchKeysPartial(keys, command.keys)) {
629
+ if (keys.length < command.keys.length) {
630
+ // Matches part of a multi-key command. Buffer and wait for next
631
+ // stroke.
632
+ inputState.keyBuffer.push(key);
633
+ return null;
634
+ } else {
635
+ if (inputState.operator && command.type == 'action') {
636
+ // Ignore matched action commands after an operator. Operators
637
+ // only operate on motions. This check is really for text
638
+ // objects since aW, a[ etcs conflicts with a.
639
+ continue;
640
+ }
641
+ // Matches whole comand. Return the command.
642
+ if (command.keys[keys.length - 1] == 'character') {
643
+ inputState.selectedCharacter = keys[keys.length - 1];
644
+ if(inputState.selectedCharacter.length>1){
645
+ switch(inputState.selectedCharacter){
646
+ case "Enter":
647
+ inputState.selectedCharacter='\n';
648
+ break;
649
+ case "Space":
650
+ inputState.selectedCharacter=' ';
651
+ break;
652
+ default:
653
+ continue;
654
+ }
655
+ }
656
+ }
657
+ inputState.keyBuffer = [];
658
+ return command;
659
+ }
660
+ }
661
+ }
662
+ // Clear the buffer since there are no partial matches.
663
+ inputState.keyBuffer = [];
664
+ return null;
665
+ },
666
+ processCommand: function(cm, vim, command) {
667
+ vim.inputState.repeatOverride = command.repeatOverride;
668
+ switch (command.type) {
669
+ case 'motion':
670
+ this.processMotion(cm, vim, command);
671
+ break;
672
+ case 'operator':
673
+ this.processOperator(cm, vim, command);
674
+ break;
675
+ case 'operatorMotion':
676
+ this.processOperatorMotion(cm, vim, command);
677
+ break;
678
+ case 'action':
679
+ this.processAction(cm, vim, command);
680
+ break;
681
+ case 'search':
682
+ this.processSearch(cm, vim, command);
683
+ break;
684
+ case 'ex':
685
+ case 'keyToEx':
686
+ this.processEx(cm, vim, command);
687
+ break;
688
+ default:
689
+ break;
690
+ }
691
+ },
692
+ processMotion: function(cm, vim, command) {
693
+ vim.inputState.motion = command.motion;
694
+ vim.inputState.motionArgs = copyArgs(command.motionArgs);
695
+ this.evalInput(cm, vim);
696
+ },
697
+ processOperator: function(cm, vim, command) {
698
+ var inputState = vim.inputState;
699
+ if (inputState.operator) {
700
+ if (inputState.operator == command.operator) {
701
+ // Typing an operator twice like 'dd' makes the operator operate
702
+ // linewise
703
+ inputState.motion = 'expandToLine';
704
+ inputState.motionArgs = { linewise: true };
705
+ this.evalInput(cm, vim);
706
+ return;
707
+ } else {
708
+ // 2 different operators in a row doesn't make sense.
709
+ vim.inputState = new InputState();
710
+ }
711
+ }
712
+ inputState.operator = command.operator;
713
+ inputState.operatorArgs = copyArgs(command.operatorArgs);
714
+ if (vim.visualMode) {
715
+ // Operating on a selection in visual mode. We don't need a motion.
716
+ this.evalInput(cm, vim);
717
+ }
718
+ },
719
+ processOperatorMotion: function(cm, vim, command) {
720
+ var visualMode = vim.visualMode;
721
+ var operatorMotionArgs = copyArgs(command.operatorMotionArgs);
722
+ if (operatorMotionArgs) {
723
+ // Operator motions may have special behavior in visual mode.
724
+ if (visualMode && operatorMotionArgs.visualLine) {
725
+ vim.visualLine = true;
726
+ }
727
+ }
728
+ this.processOperator(cm, vim, command);
729
+ if (!visualMode) {
730
+ this.processMotion(cm, vim, command);
731
+ }
732
+ },
733
+ processAction: function(cm, vim, command) {
734
+ var inputState = vim.inputState;
735
+ var repeat = inputState.getRepeat();
736
+ var repeatIsExplicit = !!repeat;
737
+ var actionArgs = copyArgs(command.actionArgs) || {};
738
+ if (inputState.selectedCharacter) {
739
+ actionArgs.selectedCharacter = inputState.selectedCharacter;
740
+ }
741
+ // Actions may or may not have motions and operators. Do these first.
742
+ if (command.operator) {
743
+ this.processOperator(cm, vim, command);
744
+ }
745
+ if (command.motion) {
746
+ this.processMotion(cm, vim, command);
747
+ }
748
+ if (command.motion || command.operator) {
749
+ this.evalInput(cm, vim);
750
+ }
751
+ actionArgs.repeat = repeat || 1;
752
+ actionArgs.repeatIsExplicit = repeatIsExplicit;
753
+ actionArgs.registerName = inputState.registerName;
754
+ vim.inputState = new InputState();
755
+ vim.lastMotion = null,
756
+ actions[command.action](cm, actionArgs, vim);
757
+ },
758
+ processSearch: function(cm, vim, command) {
759
+ if (!cm.getSearchCursor) {
760
+ // Search depends on SearchCursor.
761
+ return;
762
+ }
763
+ var forward = command.searchArgs.forward;
764
+ getSearchState(cm).setReversed(!forward);
765
+ var promptPrefix = (forward) ? '/' : '?';
766
+ var originalQuery = getSearchState(cm).getQuery();
767
+ var originalScrollPos = cm.getScrollInfo();
768
+ function handleQuery(query, ignoreCase, smartCase) {
769
+ try {
770
+ updateSearchQuery(cm, query, ignoreCase, smartCase);
771
+ } catch (e) {
772
+ showConfirm(cm, 'Invalid regex: ' + regexPart);
773
+ return;
774
+ }
775
+ commandDispatcher.processMotion(cm, vim, {
776
+ type: 'motion',
777
+ motion: 'findNext',
778
+ motionArgs: { forward: true }
779
+ });
780
+ }
781
+ function onPromptClose(query) {
782
+ cm.scrollTo(originalScrollPos.left, originalScrollPos.top);
783
+ handleQuery(query, true /** ignoreCase */, true /** smartCase */);
784
+ }
785
+ function onPromptKeyUp(e, query) {
786
+ var parsedQuery;
787
+ try {
788
+ parsedQuery = updateSearchQuery(cm, query,
789
+ true /** ignoreCase */, true /** smartCase */)
790
+ } catch (e) {
791
+ // Swallow bad regexes for incremental search.
792
+ }
793
+ if (parsedQuery) {
794
+ cm.scrollIntoView(findNext(cm, !forward, parsedQuery), 30);
795
+ } else {
796
+ clearSearchHighlight(cm);
797
+ cm.scrollTo(originalScrollPos.left, originalScrollPos.top);
798
+ }
799
+ }
800
+ function onPromptKeyDown(e, query, close) {
801
+ var keyName = CodeMirror.keyName(e);
802
+ if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') {
803
+ updateSearchQuery(cm, originalQuery);
804
+ clearSearchHighlight(cm);
805
+ cm.scrollTo(originalScrollPos.left, originalScrollPos.top);
806
+
807
+ CodeMirror.e_stop(e);
808
+ close();
809
+ cm.focus();
810
+ }
811
+ }
812
+ switch (command.searchArgs.querySrc) {
813
+ case 'prompt':
814
+ showPrompt(cm, {
815
+ onClose: onPromptClose,
816
+ prefix: promptPrefix,
817
+ desc: searchPromptDesc,
818
+ onKeyUp: onPromptKeyUp,
819
+ onKeyDown: onPromptKeyDown
820
+ });
821
+ break;
822
+ case 'wordUnderCursor':
823
+ var word = expandWordUnderCursor(cm, false /** inclusive */,
824
+ true /** forward */, false /** bigWord */,
825
+ true /** noSymbol */);
826
+ var isKeyword = true;
827
+ if (!word) {
828
+ word = expandWordUnderCursor(cm, false /** inclusive */,
829
+ true /** forward */, false /** bigWord */,
830
+ false /** noSymbol */);
831
+ isKeyword = false;
832
+ }
833
+ if (!word) {
834
+ return;
835
+ }
836
+ var query = cm.getLine(word.start.line).substring(word.start.ch,
837
+ word.end.ch + 1);
838
+ if (isKeyword) {
839
+ query = '\\b' + query + '\\b';
840
+ } else {
841
+ query = escapeRegex(query);
842
+ }
843
+ cm.setCursor(word.start);
844
+ handleQuery(query, true /** ignoreCase */, false /** smartCase */);
845
+ break;
846
+ }
847
+ },
848
+ processEx: function(cm, vim, command) {
849
+ function onPromptClose(input) {
850
+ exCommandDispatcher.processCommand(cm, input);
851
+ }
852
+ function onPromptKeyDown(e, input, close) {
853
+ var keyName = CodeMirror.keyName(e);
854
+ if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') {
855
+ CodeMirror.e_stop(e);
856
+ close();
857
+ cm.focus();
858
+ }
859
+ }
860
+ if (command.type == 'keyToEx') {
861
+ // Handle user defined Ex to Ex mappings
862
+ exCommandDispatcher.processCommand(cm, command.exArgs.input);
863
+ } else {
864
+ if (vim.visualMode) {
865
+ showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>',
866
+ onKeyDown: onPromptKeyDown});
867
+ } else {
868
+ showPrompt(cm, { onClose: onPromptClose, prefix: ':',
869
+ onKeyDown: onPromptKeyDown});
870
+ }
871
+ }
872
+ },
873
+ evalInput: function(cm, vim) {
874
+ // If the motion comand is set, execute both the operator and motion.
875
+ // Otherwise return.
876
+ var inputState = vim.inputState;
877
+ var motion = inputState.motion;
878
+ var motionArgs = inputState.motionArgs || {};
879
+ var operator = inputState.operator;
880
+ var operatorArgs = inputState.operatorArgs || {};
881
+ var registerName = inputState.registerName;
882
+ var selectionEnd = cm.getCursor('head');
883
+ var selectionStart = cm.getCursor('anchor');
884
+ // The difference between cur and selection cursors are that cur is
885
+ // being operated on and ignores that there is a selection.
886
+ var curStart = copyCursor(selectionEnd);
887
+ var curOriginal = copyCursor(curStart);
888
+ var curEnd;
889
+ var repeat;
890
+ if (operator) {
891
+ this.recordLastEdit(cm, vim, inputState);
892
+ }
893
+ if (inputState.repeatOverride !== undefined) {
894
+ // If repeatOverride is specified, that takes precedence over the
895
+ // input state's repeat. Used by Ex mode and can be user defined.
896
+ repeat = inputState.repeatOverride;
897
+ } else {
898
+ repeat = inputState.getRepeat();
899
+ }
900
+ if (repeat > 0 && motionArgs.explicitRepeat) {
901
+ motionArgs.repeatIsExplicit = true;
902
+ } else if (motionArgs.noRepeat ||
903
+ (!motionArgs.explicitRepeat && repeat === 0)) {
904
+ repeat = 1;
905
+ motionArgs.repeatIsExplicit = false;
906
+ }
907
+ if (inputState.selectedCharacter) {
908
+ // If there is a character input, stick it in all of the arg arrays.
909
+ motionArgs.selectedCharacter = operatorArgs.selectedCharacter =
910
+ inputState.selectedCharacter;
911
+ }
912
+ motionArgs.repeat = repeat;
913
+ vim.inputState = new InputState();
914
+ if (motion) {
915
+ var motionResult = motions[motion](cm, motionArgs, vim);
916
+ vim.lastMotion = motions[motion];
917
+ if (!motionResult) {
918
+ return;
919
+ }
920
+ if (motionResult instanceof Array) {
921
+ curStart = motionResult[0];
922
+ curEnd = motionResult[1];
923
+ } else {
924
+ curEnd = motionResult;
925
+ }
926
+ // TODO: Handle null returns from motion commands better.
927
+ if (!curEnd) {
928
+ curEnd = { ch: curStart.ch, line: curStart.line };
929
+ }
930
+ if (vim.visualMode) {
931
+ // Check if the selection crossed over itself. Will need to shift
932
+ // the start point if that happened.
933
+ if (cursorIsBefore(selectionStart, selectionEnd) &&
934
+ (cursorEqual(selectionStart, curEnd) ||
935
+ cursorIsBefore(curEnd, selectionStart))) {
936
+ // The end of the selection has moved from after the start to
937
+ // before the start. We will shift the start right by 1.
938
+ selectionStart.ch += 1;
939
+ } else if (cursorIsBefore(selectionEnd, selectionStart) &&
940
+ (cursorEqual(selectionStart, curEnd) ||
941
+ cursorIsBefore(selectionStart, curEnd))) {
942
+ // The opposite happened. We will shift the start left by 1.
943
+ selectionStart.ch -= 1;
944
+ }
945
+ selectionEnd = curEnd;
946
+ if (vim.visualLine) {
947
+ if (cursorIsBefore(selectionStart, selectionEnd)) {
948
+ selectionStart.ch = 0;
949
+ selectionEnd.ch = lineLength(cm, selectionEnd.line);
950
+ } else {
951
+ selectionEnd.ch = 0;
952
+ selectionStart.ch = lineLength(cm, selectionStart.line);
953
+ }
954
+ }
955
+ cm.setSelection(selectionStart, selectionEnd);
956
+ updateMark(cm, vim, '<',
957
+ cursorIsBefore(selectionStart, selectionEnd) ? selectionStart
958
+ : selectionEnd);
959
+ updateMark(cm, vim, '>',
960
+ cursorIsBefore(selectionStart, selectionEnd) ? selectionEnd
961
+ : selectionStart);
962
+ } else if (!operator) {
963
+ curEnd = clipCursorToContent(cm, curEnd);
964
+ cm.setCursor(curEnd.line, curEnd.ch);
965
+ }
966
+ }
967
+
968
+ if (operator) {
969
+ var inverted = false;
970
+ vim.lastMotion = null;
971
+ operatorArgs.repeat = repeat; // Indent in visual mode needs this.
972
+ if (vim.visualMode) {
973
+ curStart = selectionStart;
974
+ curEnd = selectionEnd;
975
+ motionArgs.inclusive = true;
976
+ }
977
+ // Swap start and end if motion was backward.
978
+ if (cursorIsBefore(curEnd, curStart)) {
979
+ var tmp = curStart;
980
+ curStart = curEnd;
981
+ curEnd = tmp;
982
+ inverted = true;
983
+ }
984
+ if (motionArgs.inclusive && !(vim.visualMode && inverted)) {
985
+ // Move the selection end one to the right to include the last
986
+ // character.
987
+ curEnd.ch++;
988
+ }
989
+ var linewise = motionArgs.linewise ||
990
+ (vim.visualMode && vim.visualLine);
991
+ if (linewise) {
992
+ // Expand selection to entire line.
993
+ expandSelectionToLine(cm, curStart, curEnd);
994
+ } else if (motionArgs.forward) {
995
+ // Clip to trailing newlines only if we the motion goes forward.
996
+ clipToLine(cm, curStart, curEnd);
997
+ }
998
+ operatorArgs.registerName = registerName;
999
+ // Keep track of linewise as it affects how paste and change behave.
1000
+ operatorArgs.linewise = linewise;
1001
+ operators[operator](cm, operatorArgs, vim, curStart,
1002
+ curEnd, curOriginal);
1003
+ if (vim.visualMode) {
1004
+ exitVisualMode(cm, vim);
1005
+ }
1006
+ if (operatorArgs.enterInsertMode) {
1007
+ actions.enterInsertMode(cm);
1008
+ }
1009
+ }
1010
+ },
1011
+ recordLastEdit: function(cm, vim, inputState) {
1012
+ vim.lastEdit = inputState;
1013
+ }
1014
+ };
1015
+
1016
+ /**
1017
+ * typedef {Object{line:number,ch:number}} Cursor An object containing the
1018
+ * position of the cursor.
1019
+ */
1020
+ // All of the functions below return Cursor objects.
1021
+ var motions = {
1022
+ moveToTopLine: function(cm, motionArgs) {
1023
+ var line = getUserVisibleLines(cm).top + motionArgs.repeat -1;
1024
+ return { line: line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(line)) };
1025
+ },
1026
+ moveToMiddleLine: function(cm) {
1027
+ var range = getUserVisibleLines(cm);
1028
+ var line = Math.floor((range.top + range.bottom) * 0.5);
1029
+ return { line: line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(line)) };
1030
+ },
1031
+ moveToBottomLine: function(cm, motionArgs) {
1032
+ var line = getUserVisibleLines(cm).bottom - motionArgs.repeat +1;
1033
+ return { line: line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(line)) };
1034
+ },
1035
+ expandToLine: function(cm, motionArgs) {
1036
+ // Expands forward to end of line, and then to next line if repeat is
1037
+ // >1. Does not handle backward motion!
1038
+ var cur = cm.getCursor();
1039
+ return { line: cur.line + motionArgs.repeat - 1, ch: Infinity };
1040
+ },
1041
+ findNext: function(cm, motionArgs, vim) {
1042
+ var state = getSearchState(cm);
1043
+ var query = state.getQuery();
1044
+ if (!query) {
1045
+ return;
1046
+ }
1047
+ var prev = !motionArgs.forward;
1048
+ // If search is initiated with ? instead of /, negate direction.
1049
+ prev = (state.isReversed()) ? !prev : prev;
1050
+ highlightSearchMatches(cm, query);
1051
+ return findNext(cm, prev/** prev */, query, motionArgs.repeat);
1052
+ },
1053
+ goToMark: function(cm, motionArgs, vim) {
1054
+ var mark = vim.marks[motionArgs.selectedCharacter];
1055
+ if (mark) {
1056
+ return mark.find();
1057
+ }
1058
+ return null;
1059
+ },
1060
+ jumpToMark: function(cm, motionArgs, vim) {
1061
+ var best = cm.getCursor();
1062
+ for (var i = 0; i < motionArgs.repeat; i++) {
1063
+ var cursor = best;
1064
+ for (var key in vim.marks) {
1065
+ if (!isLowerCase(key)) {
1066
+ continue;
1067
+ }
1068
+ var mark = vim.marks[key].find();
1069
+ var isWrongDirection = (motionArgs.forward) ?
1070
+ cursorIsBefore(mark, cursor) : cursorIsBefore(cursor, mark)
1071
+
1072
+ if (isWrongDirection) {
1073
+ continue;
1074
+ }
1075
+ if (motionArgs.linewise && (mark.line == cursor.line)) {
1076
+ continue;
1077
+ }
1078
+
1079
+ var equal = cursorEqual(cursor, best);
1080
+ var between = (motionArgs.forward) ?
1081
+ cusrorIsBetween(cursor, mark, best) :
1082
+ cusrorIsBetween(best, mark, cursor);
1083
+
1084
+ if (equal || between) {
1085
+ best = mark;
1086
+ }
1087
+ }
1088
+ }
1089
+
1090
+ if (motionArgs.linewise) {
1091
+ // Vim places the cursor on the first non-whitespace character of
1092
+ // the line if there is one, else it places the cursor at the end
1093
+ // of the line, regardless of whether a mark was found.
1094
+ best.ch = findFirstNonWhiteSpaceCharacter(cm.getLine(best.line));
1095
+ }
1096
+ return best;
1097
+ },
1098
+ moveByCharacters: function(cm, motionArgs) {
1099
+ var cur = cm.getCursor();
1100
+ var repeat = motionArgs.repeat;
1101
+ var ch = motionArgs.forward ? cur.ch + repeat : cur.ch - repeat;
1102
+ return { line: cur.line, ch: ch };
1103
+ },
1104
+ moveByLines: function(cm, motionArgs, vim) {
1105
+ var cur = cm.getCursor();
1106
+ var endCh = cur.ch;
1107
+ // Depending what our last motion was, we may want to do different
1108
+ // things. If our last motion was moving vertically, we want to
1109
+ // preserve the HPos from our last horizontal move. If our last motion
1110
+ // was going to the end of a line, moving vertically we should go to
1111
+ // the end of the line, etc.
1112
+ switch (vim.lastMotion) {
1113
+ case this.moveByLines:
1114
+ case this.moveByDisplayLines:
1115
+ case this.moveByScroll:
1116
+ case this.moveToColumn:
1117
+ case this.moveToEol:
1118
+ endCh = vim.lastHPos;
1119
+ break;
1120
+ default:
1121
+ vim.lastHPos = endCh;
1122
+ }
1123
+ var repeat = motionArgs.repeat+(motionArgs.repeatOffset||0);
1124
+ var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat;
1125
+ if (line < cm.firstLine() || line > cm.lastLine() ) {
1126
+ return null;
1127
+ }
1128
+ if(motionArgs.toFirstChar){
1129
+ endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line));
1130
+ vim.lastHPos = endCh;
1131
+ }
1132
+ vim.lastHSPos = cm.charCoords({line:line, ch:endCh},"div").left;
1133
+ return { line: line, ch: endCh };
1134
+ },
1135
+ moveByDisplayLines: function(cm, motionArgs, vim) {
1136
+ var cur = cm.getCursor();
1137
+ switch (vim.lastMotion) {
1138
+ case this.moveByDisplayLines:
1139
+ case this.moveByScroll:
1140
+ case this.moveByLines:
1141
+ case this.moveToColumn:
1142
+ case this.moveToEol:
1143
+ break;
1144
+ default:
1145
+ vim.lastHSPos = cm.charCoords(cur,"div").left;
1146
+ }
1147
+ var repeat = motionArgs.repeat;
1148
+ var res=cm.findPosV(cur,(motionArgs.forward ? repeat : -repeat),"line",vim.lastHSPos);
1149
+ if (res.hitSide) {
1150
+ if (motionArgs.forward) {
1151
+ var lastCharCoords = cm.charCoords(res, 'div');
1152
+ var goalCoords = { top: lastCharCoords.top + 8, left: vim.lastHSPos };
1153
+ var res = cm.coordsChar(goalCoords, 'div');
1154
+ } else {
1155
+ var resCoords = cm.charCoords({ line: cm.firstLine(), ch: 0}, 'div');
1156
+ resCoords.left = vim.lastHSPos;
1157
+ res = cm.coordsChar(resCoords, 'div');
1158
+ }
1159
+ }
1160
+ vim.lastHPos = res.ch;
1161
+ return res;
1162
+ },
1163
+ moveByPage: function(cm, motionArgs) {
1164
+ // CodeMirror only exposes functions that move the cursor page down, so
1165
+ // doing this bad hack to move the cursor and move it back. evalInput
1166
+ // will move the cursor to where it should be in the end.
1167
+ var curStart = cm.getCursor();
1168
+ var repeat = motionArgs.repeat;
1169
+ cm.moveV((motionArgs.forward ? repeat : -repeat), 'page');
1170
+ var curEnd = cm.getCursor();
1171
+ cm.setCursor(curStart);
1172
+ return curEnd;
1173
+ },
1174
+ moveByParagraph: function(cm, motionArgs) {
1175
+ var line = cm.getCursor().line;
1176
+ var repeat = motionArgs.repeat;
1177
+ var inc = motionArgs.forward ? 1 : -1;
1178
+ for (var i = 0; i < repeat; i++) {
1179
+ if ((!motionArgs.forward && line === cm.firstLine() ) ||
1180
+ (motionArgs.forward && line == cm.lastLine())) {
1181
+ break;
1182
+ }
1183
+ line += inc;
1184
+ while (line !== cm.firstLine() && line != cm.lastLine() && cm.getLine(line)) {
1185
+ line += inc;
1186
+ }
1187
+ }
1188
+ return { line: line, ch: 0 };
1189
+ },
1190
+ moveByScroll: function(cm, motionArgs, vim) {
1191
+ var globalState = getVimGlobalState();
1192
+ var scrollbox = cm.getScrollInfo();
1193
+ var curEnd = null;
1194
+ var repeat = motionArgs.repeat;
1195
+ if (!repeat) {
1196
+ repeat = scrollbox.clientHeight / (2 * cm.defaultTextHeight());
1197
+ }
1198
+ var orig = cm.charCoords(cm.getCursor(), 'local');
1199
+ motionArgs.repeat = repeat;
1200
+ var curEnd = motions.moveByDisplayLines(cm, motionArgs, vim);
1201
+ if (!curEnd) {
1202
+ return null;
1203
+ }
1204
+ var dest = cm.charCoords(curEnd, 'local');
1205
+ cm.scrollTo(null, scrollbox.top + dest.top - orig.top);
1206
+ return curEnd;
1207
+ },
1208
+ moveByWords: function(cm, motionArgs) {
1209
+ return moveToWord(cm, motionArgs.repeat, !!motionArgs.forward,
1210
+ !!motionArgs.wordEnd, !!motionArgs.bigWord);
1211
+ },
1212
+ moveTillCharacter: function(cm, motionArgs) {
1213
+ var repeat = motionArgs.repeat;
1214
+ var curEnd = moveToCharacter(cm, repeat, motionArgs.forward,
1215
+ motionArgs.selectedCharacter);
1216
+ var increment = motionArgs.forward ? -1 : 1;
1217
+ recordLastCharacterSearch(increment, motionArgs);
1218
+ if(!curEnd)return cm.getCursor();
1219
+ curEnd.ch += increment;
1220
+ return curEnd;
1221
+ },
1222
+ moveToCharacter: function(cm, motionArgs) {
1223
+ var repeat = motionArgs.repeat;
1224
+ recordLastCharacterSearch(0, motionArgs);
1225
+ return moveToCharacter(cm, repeat, motionArgs.forward,
1226
+ motionArgs.selectedCharacter) || cm.getCursor();
1227
+ },
1228
+ moveToSymbol: function(cm, motionArgs) {
1229
+ var repeat = motionArgs.repeat;
1230
+ return findSymbol(cm, repeat, motionArgs.forward,
1231
+ motionArgs.selectedCharacter) || cm.getCursor();
1232
+ },
1233
+ moveToColumn: function(cm, motionArgs, vim) {
1234
+ var repeat = motionArgs.repeat;
1235
+ // repeat is equivalent to which column we want to move to!
1236
+ vim.lastHPos = repeat - 1;
1237
+ vim.lastHSPos = cm.charCoords(cm.getCursor(),"div").left;
1238
+ return moveToColumn(cm, repeat);
1239
+ },
1240
+ moveToEol: function(cm, motionArgs, vim) {
1241
+ var cur = cm.getCursor();
1242
+ vim.lastHPos = Infinity;
1243
+ var retval={ line: cur.line + motionArgs.repeat - 1, ch: Infinity }
1244
+ var end=cm.clipPos(retval);
1245
+ end.ch--;
1246
+ vim.lastHSPos = cm.charCoords(end,"div").left;
1247
+ return retval;
1248
+ },
1249
+ moveToFirstNonWhiteSpaceCharacter: function(cm) {
1250
+ // Go to the start of the line where the text begins, or the end for
1251
+ // whitespace-only lines
1252
+ var cursor = cm.getCursor();
1253
+ return { line: cursor.line,
1254
+ ch: findFirstNonWhiteSpaceCharacter(cm.getLine(cursor.line)) };
1255
+ },
1256
+ moveToMatchedSymbol: function(cm, motionArgs) {
1257
+ var cursor = cm.getCursor();
1258
+ var symbol = cm.getLine(cursor.line).charAt(cursor.ch);
1259
+ if (isMatchableSymbol(symbol)) {
1260
+ return findMatchedSymbol(cm, cm.getCursor(), motionArgs.symbol);
1261
+ } else {
1262
+ return cursor;
1263
+ }
1264
+ },
1265
+ moveToStartOfLine: function(cm) {
1266
+ var cursor = cm.getCursor();
1267
+ return { line: cursor.line, ch: 0 };
1268
+ },
1269
+ moveToLineOrEdgeOfDocument: function(cm, motionArgs) {
1270
+ var lineNum = motionArgs.forward ? cm.lastLine() : cm.firstLine();
1271
+ if (motionArgs.repeatIsExplicit) {
1272
+ lineNum = motionArgs.repeat - cm.getOption('firstLineNumber');
1273
+ }
1274
+ return { line: lineNum,
1275
+ ch: findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum)) };
1276
+ },
1277
+ textObjectManipulation: function(cm, motionArgs) {
1278
+ var character = motionArgs.selectedCharacter;
1279
+ // Inclusive is the difference between a and i
1280
+ // TODO: Instead of using the additional text object map to perform text
1281
+ // object operations, merge the map into the defaultKeyMap and use
1282
+ // motionArgs to define behavior. Define separate entries for 'aw',
1283
+ // 'iw', 'a[', 'i[', etc.
1284
+ var inclusive = !motionArgs.textObjectInner;
1285
+ if (!textObjects[character]) {
1286
+ // No text object defined for this, don't move.
1287
+ return null;
1288
+ }
1289
+ var tmp = textObjects[character](cm, inclusive);
1290
+ var start = tmp.start;
1291
+ var end = tmp.end;
1292
+ return [start, end];
1293
+ },
1294
+ repeatLastCharacterSearch: function(cm, motionArgs) {
1295
+ var lastSearch = getVimGlobalState().lastChararacterSearch;
1296
+ var repeat = motionArgs.repeat;
1297
+ var forward = motionArgs.forward === lastSearch.forward;
1298
+ var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1);
1299
+ cm.moveH(-increment, 'char');
1300
+ motionArgs.inclusive = forward ? true : false;
1301
+ var curEnd = moveToCharacter(cm, repeat, forward, lastSearch.selectedCharacter);
1302
+ if (!curEnd) {
1303
+ cm.moveH(increment, 'char')
1304
+ return cm.getCursor();
1305
+ }
1306
+ curEnd.ch += increment;
1307
+ return curEnd;
1308
+ }
1309
+ };
1310
+
1311
+ var operators = {
1312
+ change: function(cm, operatorArgs, vim, curStart, curEnd) {
1313
+ getVimGlobalState().registerController.pushText(
1314
+ operatorArgs.registerName, 'change', cm.getRange(curStart, curEnd),
1315
+ operatorArgs.linewise);
1316
+ if (operatorArgs.linewise) {
1317
+ // Delete starting at the first nonwhitespace character of the first
1318
+ // line, instead of from the start of the first line. This way we get
1319
+ // an indent when we get into insert mode. This behavior isn't quite
1320
+ // correct because we should treat this as a completely new line, and
1321
+ // indent should be whatever codemirror thinks is the right indent.
1322
+ // But cm.indentLine doesn't seem work on empty lines.
1323
+ // TODO: Fix the above.
1324
+ curStart.ch =
1325
+ findFirstNonWhiteSpaceCharacter(cm.getLine(curStart.line));
1326
+ // Insert an additional newline so that insert mode can start there.
1327
+ // curEnd should be on the first character of the new line.
1328
+ cm.replaceRange('\n', curStart, curEnd);
1329
+ } else {
1330
+ cm.replaceRange('', curStart, curEnd);
1331
+ }
1332
+ cm.setCursor(curStart);
1333
+ },
1334
+ // delete is a javascript keyword.
1335
+ 'delete': function(cm, operatorArgs, vim, curStart, curEnd) {
1336
+ getVimGlobalState().registerController.pushText(
1337
+ operatorArgs.registerName, 'delete', cm.getRange(curStart, curEnd),
1338
+ operatorArgs.linewise);
1339
+ cm.replaceRange('', curStart, curEnd);
1340
+ if (operatorArgs.linewise) {
1341
+ cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
1342
+ } else {
1343
+ cm.setCursor(curStart);
1344
+ }
1345
+ },
1346
+ indent: function(cm, operatorArgs, vim, curStart, curEnd) {
1347
+ var startLine = curStart.line;
1348
+ var endLine = curEnd.line;
1349
+ // In visual mode, n> shifts the selection right n times, instead of
1350
+ // shifting n lines right once.
1351
+ var repeat = (vim.visualMode) ? operatorArgs.repeat : 1;
1352
+ if (operatorArgs.linewise) {
1353
+ // The only way to delete a newline is to delete until the start of
1354
+ // the next line, so in linewise mode evalInput will include the next
1355
+ // line. We don't want this in indent, so we go back a line.
1356
+ endLine--;
1357
+ }
1358
+ for (var i = startLine; i <= endLine; i++) {
1359
+ for (var j = 0; j < repeat; j++) {
1360
+ cm.indentLine(i, operatorArgs.indentRight);
1361
+ }
1362
+ }
1363
+ cm.setCursor(curStart);
1364
+ cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
1365
+ },
1366
+ swapcase: function(cm, operatorArgs, vim, curStart, curEnd, curOriginal) {
1367
+ var toSwap = cm.getRange(curStart, curEnd);
1368
+ var swapped = '';
1369
+ for (var i = 0; i < toSwap.length; i++) {
1370
+ var character = toSwap.charAt(i);
1371
+ swapped += isUpperCase(character) ? character.toLowerCase() :
1372
+ character.toUpperCase();
1373
+ }
1374
+ cm.replaceRange(swapped, curStart, curEnd);
1375
+ cm.setCursor(curOriginal);
1376
+ },
1377
+ yank: function(cm, operatorArgs, vim, curStart, curEnd, curOriginal) {
1378
+ getVimGlobalState().registerController.pushText(
1379
+ operatorArgs.registerName, 'yank',
1380
+ cm.getRange(curStart, curEnd), operatorArgs.linewise);
1381
+ cm.setCursor(curOriginal);
1382
+ }
1383
+ };
1384
+
1385
+ var actions = {
1386
+ scrollToCursor: function(cm, actionArgs) {
1387
+ var lineNum = cm.getCursor().line;
1388
+ var heightProp = window.getComputedStyle(cm.getScrollerElement()).
1389
+ getPropertyValue('height');
1390
+ var height = parseInt(heightProp);
1391
+ var y = cm.charCoords({line: lineNum, ch: 0}, "local").top;
1392
+ var halfHeight = parseInt(height) / 2;
1393
+ switch (actionArgs.position) {
1394
+ case 'center': y = y - (height / 2) + 10;
1395
+ break;
1396
+ case 'bottom': y = y - height;
1397
+ break;
1398
+ case 'top': break;
1399
+ }
1400
+ cm.scrollTo(null, y);
1401
+ // The calculations are slightly off, use scrollIntoView to nudge the
1402
+ // view into the right place.
1403
+ cm.scrollIntoView();
1404
+ },
1405
+ enterInsertMode: function(cm, actionArgs) {
1406
+ var insertAt = (actionArgs) ? actionArgs.insertAt : null;
1407
+ if (insertAt == 'eol') {
1408
+ var cursor = cm.getCursor();
1409
+ cursor = { line: cursor.line, ch: lineLength(cm, cursor.line) };
1410
+ cm.setCursor(cursor);
1411
+ } else if (insertAt == 'charAfter') {
1412
+ cm.setCursor(offsetCursor(cm.getCursor(), 0, 1));
1413
+ }
1414
+ cm.setOption('keyMap', 'vim-insert');
1415
+ },
1416
+ toggleVisualMode: function(cm, actionArgs, vim) {
1417
+ var repeat = actionArgs.repeat;
1418
+ var curStart = cm.getCursor();
1419
+ var curEnd;
1420
+ // TODO: The repeat should actually select number of characters/lines
1421
+ // equal to the repeat times the size of the previous visual
1422
+ // operation.
1423
+ if (!vim.visualMode) {
1424
+ vim.visualMode = true;
1425
+ vim.visualLine = !!actionArgs.linewise;
1426
+ if (vim.visualLine) {
1427
+ curStart.ch = 0;
1428
+ curEnd = clipCursorToContent(cm, {
1429
+ line: curStart.line + repeat - 1,
1430
+ ch: lineLength(cm, curStart.line)
1431
+ }, true /** includeLineBreak */);
1432
+ } else {
1433
+ curEnd = clipCursorToContent(cm, {
1434
+ line: curStart.line,
1435
+ ch: curStart.ch + repeat
1436
+ }, true /** includeLineBreak */);
1437
+ }
1438
+ // Make the initial selection.
1439
+ if (!actionArgs.repeatIsExplicit && !vim.visualLine) {
1440
+ // This is a strange case. Here the implicit repeat is 1. The
1441
+ // following commands lets the cursor hover over the 1 character
1442
+ // selection.
1443
+ cm.setCursor(curEnd);
1444
+ cm.setSelection(curEnd, curStart);
1445
+ } else {
1446
+ cm.setSelection(curStart, curEnd);
1447
+ }
1448
+ } else {
1449
+ curStart = cm.getCursor('anchor');
1450
+ curEnd = cm.getCursor('head');
1451
+ if (!vim.visualLine && actionArgs.linewise) {
1452
+ // Shift-V pressed in characterwise visual mode. Switch to linewise
1453
+ // visual mode instead of exiting visual mode.
1454
+ vim.visualLine = true;
1455
+ curStart.ch = cursorIsBefore(curStart, curEnd) ? 0 :
1456
+ lineLength(cm, curStart.line);
1457
+ curEnd.ch = cursorIsBefore(curStart, curEnd) ?
1458
+ lineLength(cm, curEnd.line) : 0;
1459
+ cm.setSelection(curStart, curEnd);
1460
+ } else if (vim.visualLine && !actionArgs.linewise) {
1461
+ // v pressed in linewise visual mode. Switch to characterwise visual
1462
+ // mode instead of exiting visual mode.
1463
+ vim.visualLine = false;
1464
+ } else {
1465
+ exitVisualMode(cm, vim);
1466
+ }
1467
+ }
1468
+ updateMark(cm, vim, '<', cursorIsBefore(curStart, curEnd) ? curStart
1469
+ : curEnd);
1470
+ updateMark(cm, vim, '>', cursorIsBefore(curStart, curEnd) ? curEnd
1471
+ : curStart);
1472
+ },
1473
+ joinLines: function(cm, actionArgs, vim) {
1474
+ var curStart, curEnd;
1475
+ if (vim.visualMode) {
1476
+ curStart = cm.getCursor('anchor');
1477
+ curEnd = cm.getCursor('head');
1478
+ curEnd.ch = lineLength(cm, curEnd.line) - 1;
1479
+ } else {
1480
+ // Repeat is the number of lines to join. Minimum 2 lines.
1481
+ var repeat = Math.max(actionArgs.repeat, 2);
1482
+ curStart = cm.getCursor();
1483
+ curEnd = clipCursorToContent(cm, { line: curStart.line + repeat - 1,
1484
+ ch: Infinity });
1485
+ }
1486
+ var finalCh = 0;
1487
+ cm.operation(function() {
1488
+ for (var i = curStart.line; i < curEnd.line; i++) {
1489
+ finalCh = lineLength(cm, curStart.line);
1490
+ var tmp = { line: curStart.line + 1,
1491
+ ch: lineLength(cm, curStart.line + 1) };
1492
+ var text = cm.getRange(curStart, tmp);
1493
+ text = text.replace(/\n\s*/g, ' ');
1494
+ cm.replaceRange(text, curStart, tmp);
1495
+ }
1496
+ var curFinalPos = { line: curStart.line, ch: finalCh };
1497
+ cm.setCursor(curFinalPos);
1498
+ });
1499
+ },
1500
+ newLineAndEnterInsertMode: function(cm, actionArgs) {
1501
+ var insertAt = cm.getCursor();
1502
+ if (insertAt.line === cm.firstLine() && !actionArgs.after) {
1503
+ // Special case for inserting newline before start of document.
1504
+ cm.replaceRange('\n', { line: cm.firstLine(), ch: 0 });
1505
+ cm.setCursor(cm.firstLine(), 0);
1506
+ } else {
1507
+ insertAt.line = (actionArgs.after) ? insertAt.line :
1508
+ insertAt.line - 1;
1509
+ insertAt.ch = lineLength(cm, insertAt.line);
1510
+ cm.setCursor(insertAt);
1511
+ var newlineFn = CodeMirror.commands.newlineAndIndentContinueComment ||
1512
+ CodeMirror.commands.newlineAndIndent;
1513
+ newlineFn(cm);
1514
+ }
1515
+ this.enterInsertMode(cm);
1516
+ },
1517
+ paste: function(cm, actionArgs, vim) {
1518
+ var cur = cm.getCursor();
1519
+ var register = getVimGlobalState().registerController.getRegister(
1520
+ actionArgs.registerName);
1521
+ if (!register.text) {
1522
+ return;
1523
+ }
1524
+ for (var text = '', i = 0; i < actionArgs.repeat; i++) {
1525
+ text += register.text;
1526
+ }
1527
+ var linewise = register.linewise;
1528
+ if (linewise) {
1529
+ if (actionArgs.after) {
1530
+ // Move the newline at the end to the start instead, and paste just
1531
+ // before the newline character of the line we are on right now.
1532
+ text = '\n' + text.slice(0, text.length - 1);
1533
+ cur.ch = lineLength(cm, cur.line);
1534
+ } else {
1535
+ cur.ch = 0;
1536
+ }
1537
+ } else {
1538
+ cur.ch += actionArgs.after ? 1 : 0;
1539
+ }
1540
+ cm.replaceRange(text, cur);
1541
+ // Now fine tune the cursor to where we want it.
1542
+ var curPosFinal;
1543
+ var idx;
1544
+ if (linewise && actionArgs.after) {
1545
+ curPosFinal = { line: cur.line + 1,
1546
+ ch: findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line + 1)) };
1547
+ } else if (linewise && !actionArgs.after) {
1548
+ curPosFinal = { line: cur.line,
1549
+ ch: findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line)) };
1550
+ } else if (!linewise && actionArgs.after) {
1551
+ idx = cm.indexFromPos(cur);
1552
+ curPosFinal = cm.posFromIndex(idx + text.length - 1);
1553
+ } else {
1554
+ idx = cm.indexFromPos(cur);
1555
+ curPosFinal = cm.posFromIndex(idx + text.length);
1556
+ }
1557
+ cm.setCursor(curPosFinal);
1558
+ },
1559
+ undo: function(cm, actionArgs) {
1560
+ repeatFn(cm, CodeMirror.commands.undo, actionArgs.repeat)();
1561
+ },
1562
+ redo: function(cm, actionArgs) {
1563
+ repeatFn(cm, CodeMirror.commands.redo, actionArgs.repeat)();
1564
+ },
1565
+ setRegister: function(cm, actionArgs, vim) {
1566
+ vim.inputState.registerName = actionArgs.selectedCharacter;
1567
+ },
1568
+ setMark: function(cm, actionArgs, vim) {
1569
+ var markName = actionArgs.selectedCharacter;
1570
+ updateMark(cm, vim, markName, cm.getCursor());
1571
+ },
1572
+ replace: function(cm, actionArgs, vim) {
1573
+ var replaceWith = actionArgs.selectedCharacter;
1574
+ var curStart = cm.getCursor();
1575
+ var replaceTo;
1576
+ var curEnd;
1577
+ if(vim.visualMode){
1578
+ curStart=cm.getCursor('start');
1579
+ curEnd=cm.getCursor('end');
1580
+ // workaround to catch the character under the cursor
1581
+ // existing workaround doesn't cover actions
1582
+ curEnd=cm.clipPos({line: curEnd.line, ch: curEnd.ch+1});
1583
+ }else{
1584
+ var line = cm.getLine(curStart.line);
1585
+ replaceTo = curStart.ch + actionArgs.repeat;
1586
+ if (replaceTo > line.length) {
1587
+ replaceTo=line.length;
1588
+ }
1589
+ curEnd = { line: curStart.line, ch: replaceTo };
1590
+ }
1591
+ if(replaceWith=='\n'){
1592
+ if(!vim.visualMode) cm.replaceRange('', curStart, curEnd);
1593
+ // special case, where vim help says to replace by just one line-break
1594
+ (CodeMirror.commands.newlineAndIndentContinueComment || CodeMirror.commands.newlineAndIndent)(cm);
1595
+ }else {
1596
+ var replaceWithStr=cm.getRange(curStart, curEnd);
1597
+ //replace all characters in range by selected, but keep linebreaks
1598
+ replaceWithStr=replaceWithStr.replace(/[^\n]/g,replaceWith);
1599
+ cm.replaceRange(replaceWithStr, curStart, curEnd);
1600
+ if(vim.visualMode){
1601
+ cm.setCursor(curStart);
1602
+ exitVisualMode(cm,vim);
1603
+ }else{
1604
+ cm.setCursor(offsetCursor(curEnd, 0, -1));
1605
+ }
1606
+ }
1607
+ },
1608
+ incrementNumberToken: function(cm, actionArgs, vim) {
1609
+ var cur = cm.getCursor();
1610
+ var lineStr = cm.getLine(cur.line);
1611
+ var re = /-?\d+/g;
1612
+ var match;
1613
+ var start;
1614
+ var end;
1615
+ var numberStr;
1616
+ var token;
1617
+ while ((match = re.exec(lineStr)) !== null) {
1618
+ token = match[0];
1619
+ start = match.index;
1620
+ end = start + token.length;
1621
+ if(cur.ch < end)break;
1622
+ }
1623
+ if(!actionArgs.backtrack && (end <= cur.ch))return;
1624
+ if (token) {
1625
+ var increment = actionArgs.increase ? 1 : -1;
1626
+ var number = parseInt(token) + (increment * actionArgs.repeat);
1627
+ var from = {ch:start, line:cur.line};
1628
+ var to = {ch:end, line:cur.line};
1629
+ numberStr = number.toString();
1630
+ cm.replaceRange(numberStr, from, to);
1631
+ } else {
1632
+ return;
1633
+ }
1634
+ cm.setCursor({line: cur.line, ch: start + numberStr.length - 1});
1635
+ },
1636
+ repeatLastEdit: function(cm, actionArgs, vim) {
1637
+ // TODO: Make this repeat insert mode changes.
1638
+ var lastEdit = vim.lastEdit;
1639
+ if (lastEdit) {
1640
+ if (actionArgs.repeat && actionArgs.repeatIsExplicit) {
1641
+ vim.lastEdit.repeatOverride = actionArgs.repeat;
1642
+ }
1643
+ var currentInputState = vim.inputState;
1644
+ vim.inputState = vim.lastEdit;
1645
+ commandDispatcher.evalInput(cm, vim);
1646
+ vim.inputState = currentInputState;
1647
+ }
1648
+ }
1649
+ };
1650
+
1651
+ var textObjects = {
1652
+ // TODO: lots of possible exceptions that can be thrown here. Try da(
1653
+ // outside of a () block.
1654
+ // TODO: implement text objects for the reverse like }. Should just be
1655
+ // an additional mapping after moving to the defaultKeyMap.
1656
+ 'w': function(cm, inclusive) {
1657
+ return expandWordUnderCursor(cm, inclusive, true /** forward */,
1658
+ false /** bigWord */);
1659
+ },
1660
+ 'W': function(cm, inclusive) {
1661
+ return expandWordUnderCursor(cm, inclusive,
1662
+ true /** forward */, true /** bigWord */);
1663
+ },
1664
+ '{': function(cm, inclusive) {
1665
+ return selectCompanionObject(cm, '}', inclusive);
1666
+ },
1667
+ '(': function(cm, inclusive) {
1668
+ return selectCompanionObject(cm, ')', inclusive);
1669
+ },
1670
+ '[': function(cm, inclusive) {
1671
+ return selectCompanionObject(cm, ']', inclusive);
1672
+ },
1673
+ '\'': function(cm, inclusive) {
1674
+ return findBeginningAndEnd(cm, "'", inclusive);
1675
+ },
1676
+ '\"': function(cm, inclusive) {
1677
+ return findBeginningAndEnd(cm, '"', inclusive);
1678
+ }
1679
+ };
1680
+
1681
+ /*
1682
+ * Below are miscellaneous utility functions used by vim.js
1683
+ */
1684
+
1685
+ /**
1686
+ * Clips cursor to ensure that line is within the buffer's range
1687
+ * If includeLineBreak is true, then allow cur.ch == lineLength.
1688
+ */
1689
+ function clipCursorToContent(cm, cur, includeLineBreak) {
1690
+ var line = Math.min(Math.max(cm.firstLine(), cur.line), cm.lastLine() );
1691
+ var maxCh = lineLength(cm, line) - 1;
1692
+ maxCh = (includeLineBreak) ? maxCh + 1 : maxCh;
1693
+ var ch = Math.min(Math.max(0, cur.ch), maxCh);
1694
+ return { line: line, ch: ch };
1695
+ }
1696
+ // Merge arguments in place, for overriding arguments.
1697
+ function mergeArgs(to, from) {
1698
+ for (var prop in from) {
1699
+ if (from.hasOwnProperty(prop)) {
1700
+ to[prop] = from[prop];
1701
+ }
1702
+ }
1703
+ }
1704
+ function copyArgs(args) {
1705
+ var ret = {};
1706
+ for (var prop in args) {
1707
+ if (args.hasOwnProperty(prop)) {
1708
+ ret[prop] = args[prop];
1709
+ }
1710
+ }
1711
+ return ret;
1712
+ }
1713
+ function offsetCursor(cur, offsetLine, offsetCh) {
1714
+ return { line: cur.line + offsetLine, ch: cur.ch + offsetCh };
1715
+ }
1716
+ function arrayEq(a1, a2) {
1717
+ if (a1.length != a2.length) {
1718
+ return false;
1719
+ }
1720
+ for (var i = 0; i < a1.length; i++) {
1721
+ if (a1[i] != a2[i]) {
1722
+ return false;
1723
+ }
1724
+ }
1725
+ return true;
1726
+ }
1727
+ function matchKeysPartial(pressed, mapped) {
1728
+ for (var i = 0; i < pressed.length; i++) {
1729
+ // 'character' means any character. For mark, register commads, etc.
1730
+ if (pressed[i] != mapped[i] && mapped[i] != 'character') {
1731
+ return false;
1732
+ }
1733
+ }
1734
+ return true;
1735
+ }
1736
+ function arrayIsSubsetFromBeginning(small, big) {
1737
+ for (var i = 0; i < small.length; i++) {
1738
+ if (small[i] != big[i]) {
1739
+ return false;
1740
+ }
1741
+ }
1742
+ return true;
1743
+ }
1744
+ function repeatFn(cm, fn, repeat) {
1745
+ return function() {
1746
+ for (var i = 0; i < repeat; i++) {
1747
+ fn(cm);
1748
+ }
1749
+ };
1750
+ }
1751
+ function copyCursor(cur) {
1752
+ return { line: cur.line, ch: cur.ch };
1753
+ }
1754
+ function cursorEqual(cur1, cur2) {
1755
+ return cur1.ch == cur2.ch && cur1.line == cur2.line;
1756
+ }
1757
+ function cursorIsBefore(cur1, cur2) {
1758
+ if (cur1.line < cur2.line) {
1759
+ return true;
1760
+ } else if (cur1.line == cur2.line && cur1.ch < cur2.ch) {
1761
+ return true;
1762
+ }
1763
+ return false;
1764
+ }
1765
+ function cusrorIsBetween(cur1, cur2, cur3) {
1766
+ // returns true if cur2 is between cur1 and cur3.
1767
+ var cur1before2 = cursorIsBefore(cur1, cur2);
1768
+ var cur2before3 = cursorIsBefore(cur2, cur3);
1769
+ return cur1before2 && cur2before3;
1770
+ }
1771
+ function lineLength(cm, lineNum) {
1772
+ return cm.getLine(lineNum).length;
1773
+ }
1774
+ function reverse(s){
1775
+ return s.split("").reverse().join("");
1776
+ }
1777
+ function trim(s) {
1778
+ if (s.trim) {
1779
+ return s.trim();
1780
+ } else {
1781
+ return s.replace(/^\s+|\s+$/g, '');
1782
+ }
1783
+ }
1784
+ function escapeRegex(s) {
1785
+ return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, "\\$1");
1786
+ }
1787
+
1788
+ function exitVisualMode(cm, vim) {
1789
+ vim.visualMode = false;
1790
+ vim.visualLine = false;
1791
+ var selectionStart = cm.getCursor('anchor');
1792
+ var selectionEnd = cm.getCursor('head');
1793
+ if (!cursorEqual(selectionStart, selectionEnd)) {
1794
+ // Clear the selection and set the cursor only if the selection has not
1795
+ // already been cleared. Otherwise we risk moving the cursor somewhere
1796
+ // it's not supposed to be.
1797
+ cm.setCursor(clipCursorToContent(cm, selectionEnd));
1798
+ }
1799
+ }
1800
+
1801
+ // Remove any trailing newlines from the selection. For
1802
+ // example, with the caret at the start of the last word on the line,
1803
+ // 'dw' should word, but not the newline, while 'w' should advance the
1804
+ // caret to the first character of the next line.
1805
+ function clipToLine(cm, curStart, curEnd) {
1806
+ var selection = cm.getRange(curStart, curEnd);
1807
+ var lines = selection.split('\n');
1808
+ if (lines.length > 1 && isWhiteSpaceString(lines.pop())) {
1809
+ curEnd.line--;
1810
+ curEnd.ch = lineLength(cm, curEnd.line);
1811
+ }
1812
+ }
1813
+
1814
+ // Expand the selection to line ends.
1815
+ function expandSelectionToLine(cm, curStart, curEnd) {
1816
+ curStart.ch = 0;
1817
+ curEnd.ch = 0;
1818
+ curEnd.line++;
1819
+ }
1820
+
1821
+ function findFirstNonWhiteSpaceCharacter(text) {
1822
+ if (!text) {
1823
+ return 0;
1824
+ }
1825
+ var firstNonWS = text.search(/\S/);
1826
+ return firstNonWS == -1 ? text.length : firstNonWS;
1827
+ }
1828
+
1829
+ function expandWordUnderCursor(cm, inclusive, forward, bigWord, noSymbol) {
1830
+ var cur = cm.getCursor();
1831
+ var line = cm.getLine(cur.line);
1832
+ var idx = cur.ch;
1833
+
1834
+ // Seek to first word or non-whitespace character, depending on if
1835
+ // noSymbol is true.
1836
+ var textAfterIdx = line.substring(idx);
1837
+ var firstMatchedChar;
1838
+ if (noSymbol) {
1839
+ firstMatchedChar = textAfterIdx.search(/\w/);
1840
+ } else {
1841
+ firstMatchedChar = textAfterIdx.search(/\S/);
1842
+ }
1843
+ if (firstMatchedChar == -1) {
1844
+ return null;
1845
+ }
1846
+ idx += firstMatchedChar;
1847
+ textAfterIdx = line.substring(idx);
1848
+ var textBeforeIdx = line.substring(0, idx);
1849
+
1850
+ var matchRegex;
1851
+ // Greedy matchers for the "word" we are trying to expand.
1852
+ if (bigWord) {
1853
+ matchRegex = /^\S+/;
1854
+ } else {
1855
+ if ((/\w/).test(line.charAt(idx))) {
1856
+ matchRegex = /^\w+/;
1857
+ } else {
1858
+ matchRegex = /^[^\w\s]+/;
1859
+ }
1860
+ }
1861
+
1862
+ var wordAfterRegex = matchRegex.exec(textAfterIdx);
1863
+ var wordStart = idx;
1864
+ var wordEnd = idx + wordAfterRegex[0].length - 1;
1865
+ // TODO: Find a better way to do this. It will be slow on very long lines.
1866
+ var wordBeforeRegex = matchRegex.exec(reverse(textBeforeIdx));
1867
+ if (wordBeforeRegex) {
1868
+ wordStart -= wordBeforeRegex[0].length;
1869
+ }
1870
+
1871
+ if (inclusive) {
1872
+ wordEnd++;
1873
+ }
1874
+
1875
+ return { start: { line: cur.line, ch: wordStart },
1876
+ end: { line: cur.line, ch: wordEnd }};
1877
+ }
1878
+
1879
+ function recordLastCharacterSearch(increment, args) {
1880
+ var vimGlobalState = getVimGlobalState();
1881
+ vimGlobalState.lastChararacterSearch.increment = increment;
1882
+ vimGlobalState.lastChararacterSearch.forward = args.forward;
1883
+ vimGlobalState.lastChararacterSearch.selectedCharacter = args.selectedCharacter;
1884
+ }
1885
+
1886
+ var symbolToMode = {
1887
+ '(': 'bracket', ')': 'bracket', '{': 'bracket', '}': 'bracket',
1888
+ '[': 'section', ']': 'section',
1889
+ '*': 'comment', '/': 'comment',
1890
+ 'm': 'method', 'M': 'method',
1891
+ '#': 'preprocess'
1892
+ };
1893
+ var findSymbolModes = {
1894
+ bracket: {
1895
+ isComplete: function(state) {
1896
+ if (state.nextCh === state.symb) {
1897
+ state.depth++;
1898
+ if(state.depth >= 1)return true;
1899
+ } else if (state.nextCh === state.reverseSymb) {
1900
+ state.depth--;
1901
+ }
1902
+ return false;
1903
+ }
1904
+ },
1905
+ section: {
1906
+ init: function(state) {
1907
+ state.curMoveThrough = true;
1908
+ state.symb = (state.forward ? ']' : '[') === state.symb ? '{' : '}';
1909
+ },
1910
+ isComplete: function(state) {
1911
+ return state.index === 0 && state.nextCh === state.symb;
1912
+ }
1913
+ },
1914
+ comment: {
1915
+ isComplete: function(state) {
1916
+ var found = state.lastCh === '*' && state.nextCh === '/';
1917
+ state.lastCh = state.nextCh;
1918
+ return found;
1919
+ }
1920
+ },
1921
+ // TODO: The original Vim implementation only operates on level 1 and 2.
1922
+ // The current implementation doesn't check for code block level and
1923
+ // therefore it operates on any levels.
1924
+ method: {
1925
+ init: function(state) {
1926
+ state.symb = (state.symb === 'm' ? '{' : '}');
1927
+ state.reverseSymb = state.symb === '{' ? '}' : '{';
1928
+ },
1929
+ isComplete: function(state) {
1930
+ if(state.nextCh === state.symb)return true;
1931
+ return false;
1932
+ }
1933
+ },
1934
+ preprocess: {
1935
+ init: function(state) {
1936
+ state.index = 0;
1937
+ },
1938
+ isComplete: function(state) {
1939
+ if (state.nextCh === '#') {
1940
+ var token = state.lineText.match(/#(\w+)/)[1];
1941
+ if (token === 'endif') {
1942
+ if (state.forward && state.depth === 0) {
1943
+ return true;
1944
+ }
1945
+ state.depth++;
1946
+ } else if (token === 'if') {
1947
+ if (!state.forward && state.depth === 0) {
1948
+ return true;
1949
+ }
1950
+ state.depth--;
1951
+ }
1952
+ if(token === 'else' && state.depth === 0)return true;
1953
+ }
1954
+ return false;
1955
+ }
1956
+ }
1957
+ };
1958
+ function findSymbol(cm, repeat, forward, symb) {
1959
+ var cur = cm.getCursor();
1960
+ var increment = forward ? 1 : -1;
1961
+ var endLine = forward ? cm.lineCount() : -1;
1962
+ var curCh = cur.ch;
1963
+ var line = cur.line;
1964
+ var lineText = cm.getLine(line);
1965
+ var state = {
1966
+ lineText: lineText,
1967
+ nextCh: lineText.charAt(curCh),
1968
+ lastCh: null,
1969
+ index: curCh,
1970
+ symb: symb,
1971
+ reverseSymb: (forward ? { ')': '(', '}': '{' } : { '(': ')', '{': '}' })[symb],
1972
+ forward: forward,
1973
+ depth: 0,
1974
+ curMoveThrough: false
1975
+ };
1976
+ var mode = symbolToMode[symb];
1977
+ if(!mode)return cur;
1978
+ var init = findSymbolModes[mode].init;
1979
+ var isComplete = findSymbolModes[mode].isComplete;
1980
+ if(init)init(state);
1981
+ while (line !== endLine && repeat) {
1982
+ state.index += increment;
1983
+ state.nextCh = state.lineText.charAt(state.index);
1984
+ if (!state.nextCh) {
1985
+ line += increment;
1986
+ state.lineText = cm.getLine(line) || '';
1987
+ if (increment > 0) {
1988
+ state.index = 0;
1989
+ } else {
1990
+ var lineLen = state.lineText.length;
1991
+ state.index = (lineLen > 0) ? (lineLen-1) : 0;
1992
+ }
1993
+ state.nextCh = state.lineText.charAt(state.index);
1994
+ }
1995
+ if (isComplete(state)) {
1996
+ cur.line = line;
1997
+ cur.ch = state.index;
1998
+ repeat--;
1999
+ }
2000
+ }
2001
+ if (state.nextCh || state.curMoveThrough) {
2002
+ return { line: line, ch: state.index };
2003
+ }
2004
+ return cur;
2005
+ }
2006
+
2007
+ /*
2008
+ * Returns the boundaries of the next word. If the cursor in the middle of
2009
+ * the word, then returns the boundaries of the current word, starting at
2010
+ * the cursor. If the cursor is at the start/end of a word, and we are going
2011
+ * forward/backward, respectively, find the boundaries of the next word.
2012
+ *
2013
+ * @param {CodeMirror} cm CodeMirror object.
2014
+ * @param {Cursor} cur The cursor position.
2015
+ * @param {boolean} forward True to search forward. False to search
2016
+ * backward.
2017
+ * @param {boolean} bigWord True if punctuation count as part of the word.
2018
+ * False if only [a-zA-Z0-9] characters count as part of the word.
2019
+ * @return {Object{from:number, to:number, line: number}} The boundaries of
2020
+ * the word, or null if there are no more words.
2021
+ */
2022
+ // TODO: Treat empty lines (with no whitespace) as words.
2023
+ function findWord(cm, cur, forward, bigWord) {
2024
+ var lineNum = cur.line;
2025
+ var pos = cur.ch;
2026
+ var line = cm.getLine(lineNum);
2027
+ var dir = forward ? 1 : -1;
2028
+ var regexps = bigWord ? bigWordRegexp : wordRegexp;
2029
+
2030
+ while (true) {
2031
+ var stop = (dir > 0) ? line.length : -1;
2032
+ var wordStart = stop, wordEnd = stop;
2033
+ // Find bounds of next word.
2034
+ while (pos != stop) {
2035
+ var foundWord = false;
2036
+ for (var i = 0; i < regexps.length && !foundWord; ++i) {
2037
+ if (regexps[i].test(line.charAt(pos))) {
2038
+ wordStart = pos;
2039
+ // Advance to end of word.
2040
+ while (pos != stop && regexps[i].test(line.charAt(pos))) {
2041
+ pos += dir;
2042
+ }
2043
+ wordEnd = pos;
2044
+ foundWord = wordStart != wordEnd;
2045
+ if (wordStart == cur.ch && lineNum == cur.line &&
2046
+ wordEnd == wordStart + dir) {
2047
+ // We started at the end of a word. Find the next one.
2048
+ continue;
2049
+ } else {
2050
+ return {
2051
+ from: Math.min(wordStart, wordEnd + 1),
2052
+ to: Math.max(wordStart, wordEnd),
2053
+ line: lineNum };
2054
+ }
2055
+ }
2056
+ }
2057
+ if (!foundWord) {
2058
+ pos += dir;
2059
+ }
2060
+ }
2061
+ // Advance to next/prev line.
2062
+ lineNum += dir;
2063
+ if (!isLine(cm, lineNum)) {
2064
+ return null;
2065
+ }
2066
+ line = cm.getLine(lineNum);
2067
+ pos = (dir > 0) ? 0 : line.length;
2068
+ }
2069
+ // Should never get here.
2070
+ throw 'The impossible happened.';
2071
+ }
2072
+
2073
+ /**
2074
+ * @param {CodeMirror} cm CodeMirror object.
2075
+ * @param {int} repeat Number of words to move past.
2076
+ * @param {boolean} forward True to search forward. False to search
2077
+ * backward.
2078
+ * @param {boolean} wordEnd True to move to end of word. False to move to
2079
+ * beginning of word.
2080
+ * @param {boolean} bigWord True if punctuation count as part of the word.
2081
+ * False if only alphabet characters count as part of the word.
2082
+ * @return {Cursor} The position the cursor should move to.
2083
+ */
2084
+ function moveToWord(cm, repeat, forward, wordEnd, bigWord) {
2085
+ var cur = cm.getCursor();
2086
+ for (var i = 0; i < repeat; i++) {
2087
+ var startCh = cur.ch, startLine = cur.line, word;
2088
+ var movedToNextWord = false;
2089
+ while (!movedToNextWord) {
2090
+ // Search and advance.
2091
+ word = findWord(cm, cur, forward, bigWord);
2092
+ movedToNextWord = true;
2093
+ if (word) {
2094
+ // Move to the word we just found. If by moving to the word we end
2095
+ // up in the same spot, then move an extra character and search
2096
+ // again.
2097
+ cur.line = word.line;
2098
+ if (forward && wordEnd) {
2099
+ // 'e'
2100
+ cur.ch = word.to - 1;
2101
+ } else if (forward && !wordEnd) {
2102
+ // 'w'
2103
+ if (inRangeInclusive(cur.ch, word.from, word.to) &&
2104
+ word.line == startLine) {
2105
+ // Still on the same word. Go to the next one.
2106
+ movedToNextWord = false;
2107
+ cur.ch = word.to - 1;
2108
+ } else {
2109
+ cur.ch = word.from;
2110
+ }
2111
+ } else if (!forward && wordEnd) {
2112
+ // 'ge'
2113
+ if (inRangeInclusive(cur.ch, word.from, word.to) &&
2114
+ word.line == startLine) {
2115
+ // still on the same word. Go to the next one.
2116
+ movedToNextWord = false;
2117
+ cur.ch = word.from;
2118
+ } else {
2119
+ cur.ch = word.to;
2120
+ }
2121
+ } else if (!forward && !wordEnd) {
2122
+ // 'b'
2123
+ cur.ch = word.from;
2124
+ }
2125
+ } else {
2126
+ // No more words to be found. Move to the end.
2127
+ if (forward) {
2128
+ return { line: cur.line, ch: lineLength(cm, cur.line) };
2129
+ } else {
2130
+ return { line: cur.line, ch: 0 };
2131
+ }
2132
+ }
2133
+ }
2134
+ }
2135
+ return cur;
2136
+ }
2137
+
2138
+ function moveToCharacter(cm, repeat, forward, character) {
2139
+ var cur = cm.getCursor();
2140
+ var start = cur.ch;
2141
+ var idx;
2142
+ for (var i = 0; i < repeat; i ++) {
2143
+ var line = cm.getLine(cur.line);
2144
+ idx = charIdxInLine(start, line, character, forward, true);
2145
+ if (idx == -1) {
2146
+ return null;
2147
+ }
2148
+ start = idx;
2149
+ }
2150
+ return { line: cm.getCursor().line, ch: idx };
2151
+ }
2152
+
2153
+ function moveToColumn(cm, repeat) {
2154
+ // repeat is always >= 1, so repeat - 1 always corresponds
2155
+ // to the column we want to go to.
2156
+ var line = cm.getCursor().line;
2157
+ return clipCursorToContent(cm, { line: line, ch: repeat - 1 });
2158
+ }
2159
+
2160
+ function updateMark(cm, vim, markName, pos) {
2161
+ if (!inArray(markName, validMarks)) {
2162
+ return;
2163
+ }
2164
+ if (vim.marks[markName]) {
2165
+ vim.marks[markName].clear();
2166
+ }
2167
+ vim.marks[markName] = cm.setBookmark(pos);
2168
+ }
2169
+
2170
+ function charIdxInLine(start, line, character, forward, includeChar) {
2171
+ // Search for char in line.
2172
+ // motion_options: {forward, includeChar}
2173
+ // If includeChar = true, include it too.
2174
+ // If forward = true, search forward, else search backwards.
2175
+ // If char is not found on this line, do nothing
2176
+ var idx;
2177
+ if (forward) {
2178
+ idx = line.indexOf(character, start + 1);
2179
+ if (idx != -1 && !includeChar) {
2180
+ idx -= 1;
2181
+ }
2182
+ } else {
2183
+ idx = line.lastIndexOf(character, start - 1);
2184
+ if (idx != -1 && !includeChar) {
2185
+ idx += 1;
2186
+ }
2187
+ }
2188
+ return idx;
2189
+ }
2190
+
2191
+ function findMatchedSymbol(cm, cur, symb) {
2192
+ var line = cur.line;
2193
+ symb = symb ? symb : cm.getLine(line).charAt(cur.ch);
2194
+
2195
+ var reverseSymb = ({
2196
+ '(': ')', ')': '(',
2197
+ '[': ']', ']': '[',
2198
+ '{': '}', '}': '{'})[symb];
2199
+
2200
+ // Couldn't find a matching symbol, abort
2201
+ if (!reverseSymb) {
2202
+ return cur;
2203
+ }
2204
+
2205
+ // set our increment to move forward (+1) or backwards (-1)
2206
+ // depending on which bracket we're matching
2207
+ var increment = ({'(': 1, '{': 1, '[': 1})[symb] || -1;
2208
+ var endLine = increment === 1 ? cm.lineCount() : -1;
2209
+ var depth = 1, nextCh = symb, index = cur.ch, lineText = cm.getLine(line);
2210
+ // Simple search for closing paren--just count openings and closings till
2211
+ // we find our match
2212
+ // TODO: use info from CodeMirror to ignore closing brackets in comments
2213
+ // and quotes, etc.
2214
+ while (line !== endLine && depth > 0) {
2215
+ index += increment;
2216
+ nextCh = lineText.charAt(index);
2217
+ if (!nextCh) {
2218
+ line += increment;
2219
+ lineText = cm.getLine(line) || '';
2220
+ if (increment > 0) {
2221
+ index = 0;
2222
+ } else {
2223
+ var lineLen = lineText.length;
2224
+ index = (lineLen > 0) ? (lineLen-1) : 0;
2225
+ }
2226
+ nextCh = lineText.charAt(index);
2227
+ }
2228
+ if (nextCh === symb) {
2229
+ depth++;
2230
+ } else if (nextCh === reverseSymb) {
2231
+ depth--;
2232
+ }
2233
+ }
2234
+
2235
+ if (nextCh) {
2236
+ return { line: line, ch: index };
2237
+ }
2238
+ return cur;
2239
+ }
2240
+
2241
+ function selectCompanionObject(cm, revSymb, inclusive) {
2242
+ var cur = cm.getCursor();
2243
+
2244
+ var end = findMatchedSymbol(cm, cur, revSymb);
2245
+ var start = findMatchedSymbol(cm, end);
2246
+ start.ch += inclusive ? 1 : 0;
2247
+ end.ch += inclusive ? 0 : 1;
2248
+
2249
+ return { start: start, end: end };
2250
+ }
2251
+
2252
+ function regexLastIndexOf(string, pattern, startIndex) {
2253
+ for (var i = !startIndex ? string.length : startIndex;
2254
+ i >= 0; --i) {
2255
+ if (pattern.test(string.charAt(i))) {
2256
+ return i;
2257
+ }
2258
+ }
2259
+ return -1;
2260
+ }
2261
+
2262
+ // Takes in a symbol and a cursor and tries to simulate text objects that
2263
+ // have identical opening and closing symbols
2264
+ // TODO support across multiple lines
2265
+ function findBeginningAndEnd(cm, symb, inclusive) {
2266
+ var cur = cm.getCursor();
2267
+ var line = cm.getLine(cur.line);
2268
+ var chars = line.split('');
2269
+ var start, end, i, len;
2270
+ var firstIndex = chars.indexOf(symb);
2271
+
2272
+ // the decision tree is to always look backwards for the beginning first,
2273
+ // but if the cursor is in front of the first instance of the symb,
2274
+ // then move the cursor forward
2275
+ if (cur.ch < firstIndex) {
2276
+ cur.ch = firstIndex;
2277
+ // Why is this line even here???
2278
+ // cm.setCursor(cur.line, firstIndex+1);
2279
+ }
2280
+ // otherwise if the cursor is currently on the closing symbol
2281
+ else if (firstIndex < cur.ch && chars[cur.ch] == symb) {
2282
+ end = cur.ch; // assign end to the current cursor
2283
+ --cur.ch; // make sure to look backwards
2284
+ }
2285
+
2286
+ // if we're currently on the symbol, we've got a start
2287
+ if (chars[cur.ch] == symb && !end) {
2288
+ start = cur.ch + 1; // assign start to ahead of the cursor
2289
+ } else {
2290
+ // go backwards to find the start
2291
+ for (i = cur.ch; i > -1 && !start; i--) {
2292
+ if (chars[i] == symb) {
2293
+ start = i + 1;
2294
+ }
2295
+ }
2296
+ }
2297
+
2298
+ // look forwards for the end symbol
2299
+ if (start && !end) {
2300
+ for (i = start, len = chars.length; i < len && !end; i++) {
2301
+ if (chars[i] == symb) {
2302
+ end = i;
2303
+ }
2304
+ }
2305
+ }
2306
+
2307
+ // nothing found
2308
+ if (!start || !end) {
2309
+ return { start: cur, end: cur };
2310
+ }
2311
+
2312
+ // include the symbols
2313
+ if (inclusive) {
2314
+ --start; ++end;
2315
+ }
2316
+
2317
+ return {
2318
+ start: { line: cur.line, ch: start },
2319
+ end: { line: cur.line, ch: end }
2320
+ };
2321
+ }
2322
+
2323
+ // Search functions
2324
+ function SearchState() {}
2325
+ SearchState.prototype = {
2326
+ getQuery: function() {
2327
+ return getVimGlobalState().query;
2328
+ },
2329
+ setQuery: function(query) {
2330
+ getVimGlobalState().query = query;
2331
+ },
2332
+ getOverlay: function() {
2333
+ return this.searchOverlay;
2334
+ },
2335
+ setOverlay: function(overlay) {
2336
+ this.searchOverlay = overlay;
2337
+ },
2338
+ isReversed: function() {
2339
+ return getVimGlobalState().isReversed;
2340
+ },
2341
+ setReversed: function(reversed) {
2342
+ getVimGlobalState().isReversed = reversed;
2343
+ }
2344
+ };
2345
+ function getSearchState(cm) {
2346
+ var vim = getVimState(cm);
2347
+ return vim.searchState_ || (vim.searchState_ = new SearchState());
2348
+ }
2349
+ function dialog(cm, template, shortText, onClose, options) {
2350
+ if (cm.openDialog) {
2351
+ cm.openDialog(template, onClose, { bottom: true, value: options.value,
2352
+ onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp });
2353
+ }
2354
+ else {
2355
+ callback(prompt(shortText, ""));
2356
+ }
2357
+ }
2358
+ function findUnescapedSlashes(str) {
2359
+ var escapeNextChar = false;
2360
+ var slashes = [];
2361
+ for (var i = 0; i < str.length; i++) {
2362
+ var c = str.charAt(i);
2363
+ if (!escapeNextChar && c == '/') {
2364
+ slashes.push(i);
2365
+ }
2366
+ escapeNextChar = (c == '\\');
2367
+ }
2368
+ return slashes;
2369
+ }
2370
+ /**
2371
+ * Extract the regular expression from the query and return a Regexp object.
2372
+ * Returns null if the query is blank.
2373
+ * If ignoreCase is passed in, the Regexp object will have the 'i' flag set.
2374
+ * If smartCase is passed in, and the query contains upper case letters,
2375
+ * then ignoreCase is overridden, and the 'i' flag will not be set.
2376
+ * If the query contains the /i in the flag part of the regular expression,
2377
+ * then both ignoreCase and smartCase are ignored, and 'i' will be passed
2378
+ * through to the Regex object.
2379
+ */
2380
+ function parseQuery(cm, query, ignoreCase, smartCase) {
2381
+ // Check if the query is already a regex.
2382
+ if (query instanceof RegExp) { return query; }
2383
+ // First try to extract regex + flags from the input. If no flags found,
2384
+ // extract just the regex. IE does not accept flags directly defined in
2385
+ // the regex string in the form /regex/flags
2386
+ var slashes = findUnescapedSlashes(query);
2387
+ var regexPart;
2388
+ var forceIgnoreCase;
2389
+ if (!slashes.length) {
2390
+ // Query looks like 'regexp'
2391
+ regexPart = query;
2392
+ } else {
2393
+ // Query looks like 'regexp/...'
2394
+ regexPart = query.substring(0, slashes[0]);
2395
+ var flagsPart = query.substring(slashes[0]);
2396
+ forceIgnoreCase = (flagsPart.indexOf('i') != -1);
2397
+ }
2398
+ if (!regexPart) {
2399
+ return null;
2400
+ }
2401
+ if (smartCase) {
2402
+ ignoreCase = (/^[^A-Z]*$/).test(regexPart);
2403
+ }
2404
+ var regexp = new RegExp(regexPart,
2405
+ (ignoreCase || forceIgnoreCase) ? 'i' : undefined);
2406
+ return regexp;
2407
+ }
2408
+ function showConfirm(cm, text) {
2409
+ if (cm.openConfirm) {
2410
+ cm.openConfirm('<span style="color: red">' + text +
2411
+ '</span> <button type="button">OK</button>', function() {},
2412
+ {bottom: true});
2413
+ } else {
2414
+ alert(text);
2415
+ }
2416
+ }
2417
+ function makePrompt(prefix, desc) {
2418
+ var raw = '';
2419
+ if (prefix) {
2420
+ raw += '<span style="font-family: monospace">' + prefix + '</span>';
2421
+ }
2422
+ raw += '<input type="text"/> ' +
2423
+ '<span style="color: #888">';
2424
+ if (desc) {
2425
+ raw += '<span style="color: #888">';
2426
+ raw += desc;
2427
+ raw += '</span>';
2428
+ }
2429
+ return raw;
2430
+ }
2431
+ var searchPromptDesc = '(Javascript regexp)';
2432
+ function showPrompt(cm, options) {
2433
+ var shortText = (options.prefix || '') + ' ' + (options.desc || '');
2434
+ var prompt = makePrompt(options.prefix, options.desc);
2435
+ dialog(cm, prompt, shortText, options.onClose, options);
2436
+ }
2437
+ function regexEqual(r1, r2) {
2438
+ if (r1 instanceof RegExp && r2 instanceof RegExp) {
2439
+ var props = ["global", "multiline", "ignoreCase", "source"];
2440
+ for (var i = 0; i < props.length; i++) {
2441
+ var prop = props[i];
2442
+ if (r1[prop] !== r2[prop]) {
2443
+ return(false);
2444
+ }
2445
+ }
2446
+ return(true);
2447
+ }
2448
+ return(false);
2449
+ }
2450
+ // Returns true if the query is valid.
2451
+ function updateSearchQuery(cm, rawQuery, ignoreCase, smartCase) {
2452
+ if (!rawQuery) {
2453
+ return;
2454
+ }
2455
+ var state = getSearchState(cm);
2456
+ var query = parseQuery(cm, rawQuery, !!ignoreCase, !!smartCase);
2457
+ if (!query) {
2458
+ return;
2459
+ }
2460
+ highlightSearchMatches(cm, query);
2461
+ if (regexEqual(query, state.getQuery())) {
2462
+ return query;
2463
+ }
2464
+ state.setQuery(query);
2465
+ return query;
2466
+ }
2467
+ function searchOverlay(query) {
2468
+ if (query.source.charAt(0) == '^') {
2469
+ var matchSol = true;
2470
+ }
2471
+ return {
2472
+ token: function(stream) {
2473
+ if (matchSol && !stream.sol()) {
2474
+ stream.skipToEnd();
2475
+ return;
2476
+ }
2477
+ var match = stream.match(query, false);
2478
+ if (match) {
2479
+ if (match[0].length == 0) {
2480
+ // Matched empty string, skip to next.
2481
+ stream.next();
2482
+ return;
2483
+ }
2484
+ if (!stream.sol()) {
2485
+ // Backtrack 1 to match \b
2486
+ stream.backUp(1);
2487
+ if (!query.exec(stream.next() + match[0])) {
2488
+ stream.next();
2489
+ return null;
2490
+ }
2491
+ }
2492
+ stream.match(query);
2493
+ return "searching";
2494
+ }
2495
+ while (!stream.eol()) {
2496
+ stream.next();
2497
+ if (stream.match(query, false)) break;
2498
+ }
2499
+ },
2500
+ query: query
2501
+ };
2502
+ }
2503
+ function highlightSearchMatches(cm, query) {
2504
+ var overlay = getSearchState(cm).getOverlay();
2505
+ if (!overlay || query != overlay.query) {
2506
+ if (overlay) {
2507
+ cm.removeOverlay(overlay);
2508
+ }
2509
+ overlay = searchOverlay(query);
2510
+ cm.addOverlay(overlay);
2511
+ getSearchState(cm).setOverlay(overlay);
2512
+ }
2513
+ }
2514
+ function findNext(cm, prev, query, repeat) {
2515
+ if (repeat === undefined) { repeat = 1; }
2516
+ return cm.operation(function() {
2517
+ var pos = cm.getCursor();
2518
+ if (!prev) {
2519
+ pos.ch += 1;
2520
+ }
2521
+ var cursor = cm.getSearchCursor(query, pos);
2522
+ for (var i = 0; i < repeat; i++) {
2523
+ if (!cursor.find(prev)) {
2524
+ // SearchCursor may have returned null because it hit EOF, wrap
2525
+ // around and try again.
2526
+ cursor = cm.getSearchCursor(query,
2527
+ (prev) ? { line: cm.lastLine() } : {line: cm.firstLine(), ch: 0} );
2528
+ if (!cursor.find(prev)) {
2529
+ return;
2530
+ }
2531
+ }
2532
+ }
2533
+ return cursor.from();
2534
+ });}
2535
+ function clearSearchHighlight(cm) {
2536
+ cm.removeOverlay(getSearchState(cm).getOverlay());
2537
+ getSearchState(cm).setOverlay(null);
2538
+ }
2539
+ /**
2540
+ * Check if pos is in the specified range, INCLUSIVE.
2541
+ * Range can be specified with 1 or 2 arguments.
2542
+ * If the first range argument is an array, treat it as an array of line
2543
+ * numbers. Match pos against any of the lines.
2544
+ * If the first range argument is a number,
2545
+ * if there is only 1 range argument, check if pos has the same line
2546
+ * number
2547
+ * if there are 2 range arguments, then check if pos is in between the two
2548
+ * range arguments.
2549
+ */
2550
+ function isInRange(pos, start, end) {
2551
+ if (typeof pos != 'number') {
2552
+ // Assume it is a cursor position. Get the line number.
2553
+ pos = pos.line;
2554
+ }
2555
+ if (start instanceof Array) {
2556
+ return inArray(pos, start);
2557
+ } else {
2558
+ if (end) {
2559
+ return (pos >= start && pos <= end);
2560
+ } else {
2561
+ return pos == start;
2562
+ }
2563
+ }
2564
+ }
2565
+ function getUserVisibleLines(cm) {
2566
+ var scrollInfo = cm.getScrollInfo();
2567
+ var occludeTorleranceTop = 6;
2568
+ var occludeTorleranceBottom = 10;
2569
+ var from = cm.coordsChar({left:0, top: occludeTorleranceTop}, 'local');
2570
+ var bottomY = scrollInfo.clientHeight - occludeTorleranceBottom;
2571
+ var to = cm.coordsChar({left:0, top: bottomY}, 'local');
2572
+ return {top: from.line, bottom: to.line};
2573
+ }
2574
+
2575
+ // Ex command handling
2576
+ // Care must be taken when adding to the default Ex command map. For any
2577
+ // pair of commands that have a shared prefix, at least one of their
2578
+ // shortNames must not match the prefix of the other command.
2579
+ var defaultExCommandMap = [
2580
+ { name: 'map', type: 'builtIn' },
2581
+ { name: 'write', shortName: 'w', type: 'builtIn' },
2582
+ { name: 'undo', shortName: 'u', type: 'builtIn' },
2583
+ { name: 'redo', shortName: 'red', type: 'builtIn' },
2584
+ { name: 'substitute', shortName: 's', type: 'builtIn'},
2585
+ { name: 'nohlsearch', shortName: 'noh', type: 'builtIn'},
2586
+ { name: 'delmarks', shortName: 'delm', type: 'builtin'}
2587
+ ];
2588
+ Vim.ExCommandDispatcher = function() {
2589
+ this.buildCommandMap_();
2590
+ };
2591
+ Vim.ExCommandDispatcher.prototype = {
2592
+ processCommand: function(cm, input) {
2593
+ var inputStream = new CodeMirror.StringStream(input);
2594
+ var params = {};
2595
+ params.input = input;
2596
+ try {
2597
+ this.parseInput_(cm, inputStream, params);
2598
+ } catch(e) {
2599
+ showConfirm(cm, e);
2600
+ return;
2601
+ }
2602
+ var commandName;
2603
+ if (!params.commandName) {
2604
+ // If only a line range is defined, move to the line.
2605
+ if (params.line !== undefined) {
2606
+ commandName = 'move';
2607
+ }
2608
+ } else {
2609
+ var command = this.matchCommand_(params.commandName);
2610
+ if (command) {
2611
+ commandName = command.name;
2612
+ this.parseCommandArgs_(inputStream, params, command);
2613
+ if (command.type == 'exToKey') {
2614
+ // Handle Ex to Key mapping.
2615
+ for (var i = 0; i < command.toKeys.length; i++) {
2616
+ vim.handleKey(cm, command.toKeys[i]);
2617
+ }
2618
+ return;
2619
+ } else if (command.type == 'exToEx') {
2620
+ // Handle Ex to Ex mapping.
2621
+ this.processCommand(cm, command.toInput);
2622
+ return;
2623
+ }
2624
+ }
2625
+ }
2626
+ if (!commandName) {
2627
+ showConfirm(cm, 'Not an editor command ":' + input + '"');
2628
+ return;
2629
+ }
2630
+ exCommands[commandName](cm, params);
2631
+ },
2632
+ parseInput_: function(cm, inputStream, result) {
2633
+ inputStream.eatWhile(':');
2634
+ // Parse range.
2635
+ if (inputStream.eat('%')) {
2636
+ result.line = cm.firstLine();
2637
+ result.lineEnd = cm.lastLine();
2638
+ } else {
2639
+ result.line = this.parseLineSpec_(cm, inputStream);
2640
+ if (result.line !== undefined && inputStream.eat(',')) {
2641
+ result.lineEnd = this.parseLineSpec_(cm, inputStream);
2642
+ }
2643
+ }
2644
+
2645
+ // Parse command name.
2646
+ var commandMatch = inputStream.match(/^(\w+)/);
2647
+ if (commandMatch) {
2648
+ result.commandName = commandMatch[1];
2649
+ } else {
2650
+ result.commandName = inputStream.match(/.*/)[0];
2651
+ }
2652
+
2653
+ return result;
2654
+ },
2655
+ parseLineSpec_: function(cm, inputStream) {
2656
+ var numberMatch = inputStream.match(/^(\d+)/);
2657
+ if (numberMatch) {
2658
+ return parseInt(numberMatch[1], 10) - 1;
2659
+ }
2660
+ switch (inputStream.next()) {
2661
+ case '.':
2662
+ return cm.getCursor().line;
2663
+ case '$':
2664
+ return cm.lastLine();
2665
+ case '\'':
2666
+ var mark = getVimState(cm).marks[inputStream.next()];
2667
+ if (mark && mark.find()) {
2668
+ return mark.find().line;
2669
+ } else {
2670
+ throw "Mark not set";
2671
+ }
2672
+ break;
2673
+ default:
2674
+ inputStream.backUp(1);
2675
+ return cm.getCursor().line;
2676
+ }
2677
+ },
2678
+ parseCommandArgs_: function(inputStream, params, command) {
2679
+ if (inputStream.eol()) {
2680
+ return;
2681
+ }
2682
+ params.argString = inputStream.match(/.*/)[0];
2683
+ // Parse command-line arguments
2684
+ var delim = command.argDelimiter || /\s+/;
2685
+ var args = trim(params.argString).split(delim);
2686
+ if (args.length && args[0]) {
2687
+ params.args = args;
2688
+ }
2689
+ },
2690
+ matchCommand_: function(commandName) {
2691
+ // Return the command in the command map that matches the shortest
2692
+ // prefix of the passed in command name. The match is guaranteed to be
2693
+ // unambiguous if the defaultExCommandMap's shortNames are set up
2694
+ // correctly. (see @code{defaultExCommandMap}).
2695
+ for (var i = commandName.length; i > 0; i--) {
2696
+ var prefix = commandName.substring(0, i);
2697
+ if (this.commandMap_[prefix]) {
2698
+ var command = this.commandMap_[prefix];
2699
+ if (command.name.indexOf(commandName) === 0) {
2700
+ return command;
2701
+ }
2702
+ }
2703
+ }
2704
+ return null;
2705
+ },
2706
+ buildCommandMap_: function() {
2707
+ this.commandMap_ = {};
2708
+ for (var i = 0; i < defaultExCommandMap.length; i++) {
2709
+ var command = defaultExCommandMap[i];
2710
+ var key = command.shortName || command.name;
2711
+ this.commandMap_[key] = command;
2712
+ }
2713
+ },
2714
+ map: function(lhs, rhs) {
2715
+ if (lhs != ':' && lhs.charAt(0) == ':') {
2716
+ var commandName = lhs.substring(1);
2717
+ if (rhs != ':' && rhs.charAt(0) == ':') {
2718
+ // Ex to Ex mapping
2719
+ this.commandMap_[commandName] = {
2720
+ name: commandName,
2721
+ type: 'exToEx',
2722
+ toInput: rhs.substring(1)
2723
+ };
2724
+ } else {
2725
+ // Ex to key mapping
2726
+ this.commandMap_[commandName] = {
2727
+ name: commandName,
2728
+ type: 'exToKey',
2729
+ toKeys: parseKeyString(rhs)
2730
+ };
2731
+ }
2732
+ } else {
2733
+ if (rhs != ':' && rhs.charAt(0) == ':') {
2734
+ // Key to Ex mapping.
2735
+ defaultKeymap.unshift({
2736
+ keys: parseKeyString(lhs),
2737
+ type: 'keyToEx',
2738
+ exArgs: { input: rhs.substring(1) }});
2739
+ } else {
2740
+ // Key to key mapping
2741
+ defaultKeymap.unshift({
2742
+ keys: parseKeyString(lhs),
2743
+ type: 'keyToKey',
2744
+ toKeys: parseKeyString(rhs)
2745
+ });
2746
+ }
2747
+ }
2748
+ }
2749
+ };
2750
+
2751
+ // Converts a key string sequence of the form a<C-w>bd<Left> into Vim's
2752
+ // keymap representation.
2753
+ function parseKeyString(str) {
2754
+ var idx = 0;
2755
+ var keys = [];
2756
+ while (idx < str.length) {
2757
+ if (str.charAt(idx) != '<') {
2758
+ keys.push(str.charAt(idx));
2759
+ idx++;
2760
+ continue;
2761
+ }
2762
+ // Vim key notation here means desktop Vim key-notation.
2763
+ // See :help key-notation in desktop Vim.
2764
+ var vimKeyNotationStart = ++idx;
2765
+ while (str.charAt(idx++) != '>') {}
2766
+ var vimKeyNotation = str.substring(vimKeyNotationStart, idx - 1);
2767
+ var mod='';
2768
+ var match = (/^C-(.+)$/).exec(vimKeyNotation);
2769
+ if (match) {
2770
+ mod='Ctrl-';
2771
+ vimKeyNotation=match[1];
2772
+ }
2773
+ var key;
2774
+ switch (vimKeyNotation) {
2775
+ case 'BS':
2776
+ key = 'Backspace';
2777
+ break;
2778
+ case 'CR':
2779
+ key = 'Enter';
2780
+ break;
2781
+ case 'Del':
2782
+ key = 'Delete';
2783
+ break;
2784
+ default:
2785
+ key = vimKeyNotation;
2786
+ break;
2787
+ }
2788
+ keys.push(mod + key);
2789
+ }
2790
+ return keys;
2791
+ }
2792
+
2793
+ var exCommands = {
2794
+ map: function(cm, params) {
2795
+ var mapArgs = params.args;
2796
+ if (!mapArgs || mapArgs.length < 2) {
2797
+ if (cm) {
2798
+ showConfirm(cm, 'Invalid mapping: ' + params.input);
2799
+ }
2800
+ return;
2801
+ }
2802
+ exCommandDispatcher.map(mapArgs[0], mapArgs[1], cm);
2803
+ },
2804
+ move: function(cm, params) {
2805
+ commandDispatcher.processCommand(cm, getVimState(cm), {
2806
+ type: 'motion',
2807
+ motion: 'moveToLineOrEdgeOfDocument',
2808
+ motionArgs: { forward: false, explicitRepeat: true,
2809
+ linewise: true },
2810
+ repeatOverride: params.line+1});
2811
+ },
2812
+ substitute: function(cm, params) {
2813
+ var argString = params.argString;
2814
+ var slashes = findUnescapedSlashes(argString);
2815
+ if (slashes[0] !== 0) {
2816
+ showConfirm(cm, 'Substitutions should be of the form ' +
2817
+ ':s/pattern/replace/');
2818
+ return;
2819
+ }
2820
+ var regexPart = argString.substring(slashes[0] + 1, slashes[1]);
2821
+ var replacePart = '';
2822
+ var flagsPart;
2823
+ var count;
2824
+ if (slashes[1]) {
2825
+ replacePart = argString.substring(slashes[1] + 1, slashes[2]);
2826
+ }
2827
+ if (slashes[2]) {
2828
+ // After the 3rd slash, we can have flags followed by a space followed
2829
+ // by count.
2830
+ var trailing = argString.substring(slashes[2] + 1).split(' ');
2831
+ flagsPart = trailing[0];
2832
+ count = parseInt(trailing[1]);
2833
+ }
2834
+ if (flagsPart) {
2835
+ regexPart = regexPart + '/' + flagsPart;
2836
+ }
2837
+ if (regexPart) {
2838
+ // If regex part is empty, then use the previous query. Otherwise use
2839
+ // the regex part as the new query.
2840
+ try {
2841
+ updateSearchQuery(cm, regexPart, true /** ignoreCase */,
2842
+ true /** smartCase */);
2843
+ } catch (e) {
2844
+ showConfirm(cm, 'Invalid regex: ' + regexPart);
2845
+ return;
2846
+ }
2847
+ }
2848
+ var state = getSearchState(cm);
2849
+ var query = state.getQuery();
2850
+ var lineStart = params.line || cm.firstLine();
2851
+ var lineEnd = params.lineEnd || lineStart;
2852
+ if (count) {
2853
+ lineStart = lineEnd;
2854
+ lineEnd = lineStart + count - 1;
2855
+ }
2856
+ var startPos = clipCursorToContent(cm, { line: lineStart, ch: 0 });
2857
+ function doReplace() {
2858
+ for (var cursor = cm.getSearchCursor(query, startPos);
2859
+ cursor.findNext() &&
2860
+ isInRange(cursor.from(), lineStart, lineEnd);) {
2861
+ var text = cm.getRange(cursor.from(), cursor.to());
2862
+ var newText = text.replace(query, replacePart);
2863
+ cursor.replace(newText);
2864
+ }
2865
+ var vim = getVimState(cm);
2866
+ if (vim.visualMode) {
2867
+ exitVisualMode(cm, vim);
2868
+ }
2869
+ }
2870
+ cm.operation(doReplace);
2871
+ },
2872
+ redo: CodeMirror.commands.redo,
2873
+ undo: CodeMirror.commands.undo,
2874
+ write: function(cm) {
2875
+ if (CodeMirror.commands.save) {
2876
+ // If a save command is defined, call it.
2877
+ CodeMirror.commands.save(cm);
2878
+ } else {
2879
+ // Saves to text area if no save command is defined.
2880
+ cm.save();
2881
+ }
2882
+ },
2883
+ nohlsearch: function(cm) {
2884
+ clearSearchHighlight(cm);
2885
+ },
2886
+ delmarks: function(cm, params) {
2887
+ if (!params.argString || !params.argString.trim()) {
2888
+ showConfirm(cm, 'Argument required');
2889
+ return;
2890
+ }
2891
+
2892
+ var state = getVimState(cm);
2893
+ var stream = new CodeMirror.StringStream(params.argString.trim());
2894
+ while (!stream.eol()) {
2895
+ stream.eatSpace();
2896
+
2897
+ // Record the streams position at the beginning of the loop for use
2898
+ // in error messages.
2899
+ var count = stream.pos;
2900
+
2901
+ if (!stream.match(/[a-zA-Z]/, false)) {
2902
+ showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count));
2903
+ return;
2904
+ }
2905
+
2906
+ var sym = stream.next();
2907
+ // Check if this symbol is part of a range
2908
+ if (stream.match('-', true)) {
2909
+ // This symbol is part of a range.
2910
+
2911
+ // The range must terminate at an alphabetic character.
2912
+ if (!stream.match(/[a-zA-Z]/, false)) {
2913
+ showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count));
2914
+ return;
2915
+ }
2916
+
2917
+ var startMark = sym;
2918
+ var finishMark = stream.next();
2919
+ // The range must terminate at an alphabetic character which
2920
+ // shares the same case as the start of the range.
2921
+ if (isLowerCase(startMark) && isLowerCase(finishMark) ||
2922
+ isUpperCase(startMark) && isUpperCase(finishMark)) {
2923
+ var start = startMark.charCodeAt(0);
2924
+ var finish = finishMark.charCodeAt(0);
2925
+ if (start >= finish) {
2926
+ showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count));
2927
+ return;
2928
+ }
2929
+
2930
+ // Because marks are always ASCII values, and we have
2931
+ // determined that they are the same case, we can use
2932
+ // their char codes to iterate through the defined range.
2933
+ for (var j = 0; j <= finish - start; j++) {
2934
+ var mark = String.fromCharCode(start + j);
2935
+ delete state.marks[mark];
2936
+ }
2937
+ } else {
2938
+ showConfirm(cm, 'Invalid argument: ' + startMark + "-");
2939
+ return;
2940
+ }
2941
+ } else {
2942
+ // This symbol is a valid mark, and is not part of a range.
2943
+ delete state.marks[sym];
2944
+ }
2945
+ }
2946
+ }
2947
+ };
2948
+
2949
+ var exCommandDispatcher = new Vim.ExCommandDispatcher();
2950
+
2951
+ // Register Vim with CodeMirror
2952
+ function buildVimKeyMap() {
2953
+ /**
2954
+ * Handle the raw key event from CodeMirror. Translate the
2955
+ * Shift + key modifier to the resulting letter, while preserving other
2956
+ * modifers.
2957
+ */
2958
+ // TODO: Figure out a way to catch capslock.
2959
+ function handleKeyEvent_(cm, key, modifier) {
2960
+ if (isUpperCase(key)) {
2961
+ // Convert to lower case if shift is not the modifier since the key
2962
+ // we get from CodeMirror is always upper case.
2963
+ if (modifier == 'Shift') {
2964
+ modifier = null;
2965
+ }
2966
+ else {
2967
+ key = key.toLowerCase();
2968
+ }
2969
+ }
2970
+ if (modifier) {
2971
+ // Vim will parse modifier+key combination as a single key.
2972
+ key = modifier + '-' + key;
2973
+ }
2974
+ vim.handleKey(cm, key);
2975
+ }
2976
+
2977
+ // Closure to bind CodeMirror, key, modifier.
2978
+ function keyMapper(key, modifier) {
2979
+ return function(cm) {
2980
+ handleKeyEvent_(cm, key, modifier);
2981
+ };
2982
+ }
2983
+
2984
+ var modifiers = ['Shift', 'Ctrl'];
2985
+ var keyMap = {
2986
+ 'nofallthrough': true,
2987
+ 'style': 'fat-cursor'
2988
+ };
2989
+ function bindKeys(keys, modifier) {
2990
+ for (var i = 0; i < keys.length; i++) {
2991
+ var key = keys[i];
2992
+ if (!modifier && inArray(key, specialSymbols)) {
2993
+ // Wrap special symbols with '' because that's how CodeMirror binds
2994
+ // them.
2995
+ key = "'" + key + "'";
2996
+ }
2997
+ if (modifier) {
2998
+ keyMap[modifier + '-' + key] = keyMapper(keys[i], modifier);
2999
+ } else {
3000
+ keyMap[key] = keyMapper(keys[i]);
3001
+ }
3002
+ }
3003
+ }
3004
+ bindKeys(upperCaseAlphabet);
3005
+ bindKeys(upperCaseAlphabet, 'Shift');
3006
+ bindKeys(upperCaseAlphabet, 'Ctrl');
3007
+ bindKeys(specialSymbols);
3008
+ bindKeys(specialSymbols, 'Ctrl');
3009
+ bindKeys(numbers);
3010
+ bindKeys(numbers, 'Ctrl');
3011
+ bindKeys(specialKeys);
3012
+ bindKeys(specialKeys, 'Ctrl');
3013
+ return keyMap;
3014
+ }
3015
+ CodeMirror.keyMap.vim = buildVimKeyMap();
3016
+
3017
+ function exitInsertMode(cm) {
3018
+ cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true);
3019
+ cm.setOption('keyMap', 'vim');
3020
+ }
3021
+
3022
+ CodeMirror.keyMap['vim-insert'] = {
3023
+ // TODO: override navigation keys so that Esc will cancel automatic
3024
+ // indentation from o, O, i_<CR>
3025
+ 'Esc': exitInsertMode,
3026
+ 'Ctrl-[': exitInsertMode,
3027
+ 'Ctrl-C': exitInsertMode,
3028
+ 'Ctrl-N': 'autocomplete',
3029
+ 'Ctrl-P': 'autocomplete',
3030
+ 'Enter': function(cm) {
3031
+ var fn = CodeMirror.commands.newlineAndIndentContinueComment ||
3032
+ CodeMirror.commands.newlineAndIndent;
3033
+ fn(cm);
3034
+ },
3035
+ fallthrough: ['default']
3036
+ };
3037
+
3038
+ return vimApi;
3039
+ };
3040
+ // Initialize Vim and make it available as an API.
3041
+ var vim = Vim();
3042
+ CodeMirror.Vim = vim;
3043
+ }
3044
+ )();