ledger_web 1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +7 -0
  3. data/README.md +140 -0
  4. data/Rakefile +11 -0
  5. data/bin/ledger_web +14 -0
  6. data/ledger_web.gemspec +26 -0
  7. data/lib/ledger_web/app.rb +69 -0
  8. data/lib/ledger_web/config.rb +87 -0
  9. data/lib/ledger_web/db/migrate/20111226180900_initial_schema.rb +38 -0
  10. data/lib/ledger_web/db/migrate/20111231132900_add_views.rb +37 -0
  11. data/lib/ledger_web/db.rb +54 -0
  12. data/lib/ledger_web/helpers.rb +62 -0
  13. data/lib/ledger_web/public/bootstrap-dropdown.js +55 -0
  14. data/lib/ledger_web/public/bootstrap.min.css +356 -0
  15. data/lib/ledger_web/public/codemirror/keymap/emacs.js +29 -0
  16. data/lib/ledger_web/public/codemirror/keymap/vim.js +76 -0
  17. data/lib/ledger_web/public/codemirror/lib/codemirror.css +104 -0
  18. data/lib/ledger_web/public/codemirror/lib/codemirror.js +2761 -0
  19. data/lib/ledger_web/public/codemirror/lib/util/dialog.css +23 -0
  20. data/lib/ledger_web/public/codemirror/lib/util/dialog.js +63 -0
  21. data/lib/ledger_web/public/codemirror/lib/util/foldcode.js +66 -0
  22. data/lib/ledger_web/public/codemirror/lib/util/formatting.js +291 -0
  23. data/lib/ledger_web/public/codemirror/lib/util/javascript-hint.js +83 -0
  24. data/lib/ledger_web/public/codemirror/lib/util/overlay.js +51 -0
  25. data/lib/ledger_web/public/codemirror/lib/util/runmode.js +27 -0
  26. data/lib/ledger_web/public/codemirror/lib/util/search.js +114 -0
  27. data/lib/ledger_web/public/codemirror/lib/util/searchcursor.js +117 -0
  28. data/lib/ledger_web/public/codemirror/lib/util/simple-hint.css +16 -0
  29. data/lib/ledger_web/public/codemirror/lib/util/simple-hint.js +66 -0
  30. data/lib/ledger_web/public/codemirror/mode/clike/clike.js +249 -0
  31. data/lib/ledger_web/public/codemirror/mode/clike/index.html +101 -0
  32. data/lib/ledger_web/public/codemirror/mode/clojure/clojure.js +207 -0
  33. data/lib/ledger_web/public/codemirror/mode/clojure/index.html +66 -0
  34. data/lib/ledger_web/public/codemirror/mode/coffeescript/LICENSE +22 -0
  35. data/lib/ledger_web/public/codemirror/mode/coffeescript/coffeescript.js +325 -0
  36. data/lib/ledger_web/public/codemirror/mode/coffeescript/index.html +721 -0
  37. data/lib/ledger_web/public/codemirror/mode/css/css.js +124 -0
  38. data/lib/ledger_web/public/codemirror/mode/css/index.html +55 -0
  39. data/lib/ledger_web/public/codemirror/mode/diff/diff.css +3 -0
  40. data/lib/ledger_web/public/codemirror/mode/diff/diff.js +13 -0
  41. data/lib/ledger_web/public/codemirror/mode/diff/index.html +99 -0
  42. data/lib/ledger_web/public/codemirror/mode/gfm/gfm.js +108 -0
  43. data/lib/ledger_web/public/codemirror/mode/gfm/index.html +47 -0
  44. data/lib/ledger_web/public/codemirror/mode/groovy/groovy.js +210 -0
  45. data/lib/ledger_web/public/codemirror/mode/groovy/index.html +71 -0
  46. data/lib/ledger_web/public/codemirror/mode/haskell/haskell.js +242 -0
  47. data/lib/ledger_web/public/codemirror/mode/haskell/index.html +60 -0
  48. data/lib/ledger_web/public/codemirror/mode/htmlembedded/htmlembedded.js +68 -0
  49. data/lib/ledger_web/public/codemirror/mode/htmlembedded/index.html +49 -0
  50. data/lib/ledger_web/public/codemirror/mode/htmlmixed/htmlmixed.js +83 -0
  51. data/lib/ledger_web/public/codemirror/mode/htmlmixed/index.html +51 -0
  52. data/lib/ledger_web/public/codemirror/mode/javascript/index.html +77 -0
  53. data/lib/ledger_web/public/codemirror/mode/javascript/javascript.js +360 -0
  54. data/lib/ledger_web/public/codemirror/mode/jinja2/index.html +37 -0
  55. data/lib/ledger_web/public/codemirror/mode/jinja2/jinja2.js +42 -0
  56. data/lib/ledger_web/public/codemirror/mode/lua/index.html +72 -0
  57. data/lib/ledger_web/public/codemirror/mode/lua/lua.js +140 -0
  58. data/lib/ledger_web/public/codemirror/mode/markdown/index.html +339 -0
  59. data/lib/ledger_web/public/codemirror/mode/markdown/markdown.js +242 -0
  60. data/lib/ledger_web/public/codemirror/mode/ntriples/index.html +32 -0
  61. data/lib/ledger_web/public/codemirror/mode/ntriples/ntriples.js +172 -0
  62. data/lib/ledger_web/public/codemirror/mode/pascal/LICENSE +7 -0
  63. data/lib/ledger_web/public/codemirror/mode/pascal/index.html +48 -0
  64. data/lib/ledger_web/public/codemirror/mode/pascal/pascal.js +138 -0
  65. data/lib/ledger_web/public/codemirror/mode/perl/LICENSE +19 -0
  66. data/lib/ledger_web/public/codemirror/mode/perl/index.html +62 -0
  67. data/lib/ledger_web/public/codemirror/mode/perl/perl.js +816 -0
  68. data/lib/ledger_web/public/codemirror/mode/php/index.html +48 -0
  69. data/lib/ledger_web/public/codemirror/mode/php/php.js +120 -0
  70. data/lib/ledger_web/public/codemirror/mode/plsql/index.html +62 -0
  71. data/lib/ledger_web/public/codemirror/mode/plsql/plsql.js +217 -0
  72. data/lib/ledger_web/public/codemirror/mode/python/LICENSE.txt +21 -0
  73. data/lib/ledger_web/public/codemirror/mode/python/index.html +122 -0
  74. data/lib/ledger_web/public/codemirror/mode/python/python.js +333 -0
  75. data/lib/ledger_web/public/codemirror/mode/r/LICENSE +24 -0
  76. data/lib/ledger_web/public/codemirror/mode/r/index.html +73 -0
  77. data/lib/ledger_web/public/codemirror/mode/r/r.js +141 -0
  78. data/lib/ledger_web/public/codemirror/mode/rpm/changes/changes.js +19 -0
  79. data/lib/ledger_web/public/codemirror/mode/rpm/changes/index.html +53 -0
  80. data/lib/ledger_web/public/codemirror/mode/rpm/spec/index.html +99 -0
  81. data/lib/ledger_web/public/codemirror/mode/rpm/spec/spec.css +5 -0
  82. data/lib/ledger_web/public/codemirror/mode/rpm/spec/spec.js +66 -0
  83. data/lib/ledger_web/public/codemirror/mode/rst/index.html +525 -0
  84. data/lib/ledger_web/public/codemirror/mode/rst/rst.js +326 -0
  85. data/lib/ledger_web/public/codemirror/mode/ruby/LICENSE +24 -0
  86. data/lib/ledger_web/public/codemirror/mode/ruby/index.html +171 -0
  87. data/lib/ledger_web/public/codemirror/mode/ruby/ruby.js +195 -0
  88. data/lib/ledger_web/public/codemirror/mode/rust/index.html +48 -0
  89. data/lib/ledger_web/public/codemirror/mode/rust/rust.js +411 -0
  90. data/lib/ledger_web/public/codemirror/mode/scheme/index.html +64 -0
  91. data/lib/ledger_web/public/codemirror/mode/scheme/scheme.js +202 -0
  92. data/lib/ledger_web/public/codemirror/mode/smalltalk/index.html +55 -0
  93. data/lib/ledger_web/public/codemirror/mode/smalltalk/smalltalk.js +139 -0
  94. data/lib/ledger_web/public/codemirror/mode/sparql/index.html +40 -0
  95. data/lib/ledger_web/public/codemirror/mode/sparql/sparql.js +143 -0
  96. data/lib/ledger_web/public/codemirror/mode/stex/index.html +95 -0
  97. data/lib/ledger_web/public/codemirror/mode/stex/stex.js +167 -0
  98. data/lib/ledger_web/public/codemirror/mode/tiddlywiki/index.html +183 -0
  99. data/lib/ledger_web/public/codemirror/mode/tiddlywiki/tiddlywiki.css +21 -0
  100. data/lib/ledger_web/public/codemirror/mode/tiddlywiki/tiddlywiki.js +374 -0
  101. data/lib/ledger_web/public/codemirror/mode/velocity/index.html +103 -0
  102. data/lib/ledger_web/public/codemirror/mode/velocity/velocity.js +146 -0
  103. data/lib/ledger_web/public/codemirror/mode/xml/index.html +44 -0
  104. data/lib/ledger_web/public/codemirror/mode/xml/xml.js +252 -0
  105. data/lib/ledger_web/public/codemirror/mode/xmlpure/index.html +59 -0
  106. data/lib/ledger_web/public/codemirror/mode/xmlpure/xmlpure.js +485 -0
  107. data/lib/ledger_web/public/codemirror/mode/yaml/index.html +67 -0
  108. data/lib/ledger_web/public/codemirror/mode/yaml/yaml.js +95 -0
  109. data/lib/ledger_web/public/codemirror/theme/cobalt.css +18 -0
  110. data/lib/ledger_web/public/codemirror/theme/eclipse.css +25 -0
  111. data/lib/ledger_web/public/codemirror/theme/elegant.css +10 -0
  112. data/lib/ledger_web/public/codemirror/theme/monokai.css +28 -0
  113. data/lib/ledger_web/public/codemirror/theme/neat.css +9 -0
  114. data/lib/ledger_web/public/codemirror/theme/night.css +21 -0
  115. data/lib/ledger_web/public/codemirror/theme/rubyblue.css +21 -0
  116. data/lib/ledger_web/public/jquery-1.7.1.min.js +4 -0
  117. data/lib/ledger_web/public/jquery.tablesorter.min.js +4 -0
  118. data/lib/ledger_web/public/ledger.css +14 -0
  119. data/lib/ledger_web/report.rb +187 -0
  120. data/lib/ledger_web/reports/savings_rate.erb +49 -0
  121. data/lib/ledger_web/version.rb +3 -0
  122. data/lib/ledger_web/views/error.erb +5 -0
  123. data/lib/ledger_web/views/help.erb +6 -0
  124. data/lib/ledger_web/views/layout.erb +44 -0
  125. data/lib/ledger_web/views/table.erb +31 -0
  126. data/lib/ledger_web/watcher.rb +37 -0
  127. data/lib/ledger_web.rb +20 -0
  128. metadata +229 -0
@@ -0,0 +1,114 @@
1
+ // Define search commands. Depends on dialog.js or another
2
+ // implementation of the openDialog method.
3
+
4
+ // Replace works a little oddly -- it will do the replace on the next
5
+ // Ctrl-G (or whatever is bound to findNext) press. You prevent a
6
+ // replace by making sure the match is no longer selected when hitting
7
+ // Ctrl-G.
8
+
9
+ (function() {
10
+ function SearchState() {
11
+ this.posFrom = this.posTo = this.query = null;
12
+ this.marked = [];
13
+ }
14
+ function getSearchState(cm) {
15
+ return cm._searchState || (cm._searchState = new SearchState());
16
+ }
17
+ function dialog(cm, text, shortText, f) {
18
+ if (cm.openDialog) cm.openDialog(text, f);
19
+ else f(prompt(shortText, ""));
20
+ }
21
+ function confirmDialog(cm, text, shortText, fs) {
22
+ if (cm.openConfirm) cm.openConfirm(text, fs);
23
+ else if (confirm(shortText)) fs[0]();
24
+ }
25
+ function parseQuery(query) {
26
+ var isRE = query.match(/^\/(.*)\/$/);
27
+ return isRE ? new RegExp(isRE[1]) : query;
28
+ }
29
+ var queryDialog =
30
+ 'Search: <input type="text" style="width: 10em"> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
31
+ function doSearch(cm, rev) {
32
+ var state = getSearchState(cm);
33
+ if (state.query) return findNext(cm, rev);
34
+ dialog(cm, queryDialog, "Search for:", function(query) {
35
+ cm.operation(function() {
36
+ if (!query || state.query) return;
37
+ state.query = parseQuery(query);
38
+ if (cm.lineCount() < 2000) { // This is too expensive on big documents.
39
+ for (var cursor = cm.getSearchCursor(query); cursor.findNext();)
40
+ state.marked.push(cm.markText(cursor.from(), cursor.to(), "CodeMirror-searching"));
41
+ }
42
+ state.posFrom = state.posTo = cm.getCursor();
43
+ findNext(cm, rev);
44
+ });
45
+ });
46
+ }
47
+ function findNext(cm, rev) {cm.operation(function() {
48
+ var state = getSearchState(cm);
49
+ var cursor = cm.getSearchCursor(state.query, rev ? state.posFrom : state.posTo);
50
+ if (!cursor.find(rev)) {
51
+ cursor = cm.getSearchCursor(state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0});
52
+ if (!cursor.find(rev)) return;
53
+ }
54
+ cm.setSelection(cursor.from(), cursor.to());
55
+ state.posFrom = cursor.from(); state.posTo = cursor.to();
56
+ })}
57
+ function clearSearch(cm) {cm.operation(function() {
58
+ var state = getSearchState(cm);
59
+ if (!state.query) return;
60
+ state.query = null;
61
+ for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear();
62
+ state.marked.length = 0;
63
+ })}
64
+
65
+ var replaceQueryDialog =
66
+ 'Replace: <input type="text" style="width: 10em"> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
67
+ var replacementQueryDialog = 'With: <input type="text" style="width: 10em">';
68
+ var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
69
+ function replace(cm, all) {
70
+ dialog(cm, replaceQueryDialog, "Replace:", function(query) {
71
+ if (!query) return;
72
+ query = parseQuery(query);
73
+ dialog(cm, replacementQueryDialog, "Replace with:", function(text) {
74
+ if (all) {
75
+ cm.operation(function() {
76
+ for (var cursor = cm.getSearchCursor(query); cursor.findNext();) {
77
+ if (typeof query != "string") {
78
+ var match = cm.getRange(cursor.from(), cursor.to()).match(query);
79
+ cursor.replace(text.replace(/\$(\d)/, function(w, i) {return match[i];}));
80
+ } else cursor.replace(text);
81
+ }
82
+ });
83
+ } else {
84
+ clearSearch(cm);
85
+ var cursor = cm.getSearchCursor(query, cm.getCursor());
86
+ function advance() {
87
+ var start = cursor.from(), match;
88
+ if (!(match = cursor.findNext())) {
89
+ cursor = cm.getSearchCursor(query);
90
+ if (!(match = cursor.findNext()) ||
91
+ (cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
92
+ }
93
+ cm.setSelection(cursor.from(), cursor.to());
94
+ confirmDialog(cm, doReplaceConfirm, "Replace?",
95
+ [function() {doReplace(match);}, advance]);
96
+ }
97
+ function doReplace(match) {
98
+ cursor.replace(typeof query == "string" ? text :
99
+ text.replace(/\$(\d)/, function(w, i) {return match[i];}));
100
+ advance();
101
+ }
102
+ advance();
103
+ }
104
+ });
105
+ });
106
+ }
107
+
108
+ CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
109
+ CodeMirror.commands.findNext = doSearch;
110
+ CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
111
+ CodeMirror.commands.clearSearch = clearSearch;
112
+ CodeMirror.commands.replace = replace;
113
+ CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
114
+ })();
@@ -0,0 +1,117 @@
1
+ (function(){
2
+ function SearchCursor(cm, query, pos, caseFold) {
3
+ this.atOccurrence = false; this.cm = cm;
4
+ if (caseFold == null) caseFold = typeof query == "string" && query == query.toLowerCase();
5
+
6
+ pos = pos ? cm.clipPos(pos) : {line: 0, ch: 0};
7
+ this.pos = {from: pos, to: pos};
8
+
9
+ // The matches method is filled in based on the type of query.
10
+ // It takes a position and a direction, and returns an object
11
+ // describing the next occurrence of the query, or null if no
12
+ // more matches were found.
13
+ if (typeof query != "string") // Regexp match
14
+ this.matches = function(reverse, pos) {
15
+ if (reverse) {
16
+ var line = cm.getLine(pos.line).slice(0, pos.ch), match = line.match(query), start = 0;
17
+ while (match) {
18
+ var ind = line.indexOf(match[0]);
19
+ start += ind;
20
+ line = line.slice(ind + 1);
21
+ var newmatch = line.match(query);
22
+ if (newmatch) match = newmatch;
23
+ else break;
24
+ start++;
25
+ }
26
+ }
27
+ else {
28
+ var line = cm.getLine(pos.line).slice(pos.ch), match = line.match(query),
29
+ start = match && pos.ch + line.indexOf(match[0]);
30
+ }
31
+ if (match)
32
+ return {from: {line: pos.line, ch: start},
33
+ to: {line: pos.line, ch: start + match[0].length},
34
+ match: match};
35
+ };
36
+ else { // String query
37
+ if (caseFold) query = query.toLowerCase();
38
+ var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
39
+ var target = query.split("\n");
40
+ // Different methods for single-line and multi-line queries
41
+ if (target.length == 1)
42
+ this.matches = function(reverse, pos) {
43
+ var line = fold(cm.getLine(pos.line)), len = query.length, match;
44
+ if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
45
+ : (match = line.indexOf(query, pos.ch)) != -1)
46
+ return {from: {line: pos.line, ch: match},
47
+ to: {line: pos.line, ch: match + len}};
48
+ };
49
+ else
50
+ this.matches = function(reverse, pos) {
51
+ var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(cm.getLine(ln));
52
+ var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
53
+ if (reverse ? offsetA >= pos.ch || offsetA != match.length
54
+ : offsetA <= pos.ch || offsetA != line.length - match.length)
55
+ return;
56
+ for (;;) {
57
+ if (reverse ? !ln : ln == cm.lineCount() - 1) return;
58
+ line = fold(cm.getLine(ln += reverse ? -1 : 1));
59
+ match = target[reverse ? --idx : ++idx];
60
+ if (idx > 0 && idx < target.length - 1) {
61
+ if (line != match) return;
62
+ else continue;
63
+ }
64
+ var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
65
+ if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
66
+ return;
67
+ var start = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB};
68
+ return {from: reverse ? end : start, to: reverse ? start : end};
69
+ }
70
+ };
71
+ }
72
+ }
73
+
74
+ SearchCursor.prototype = {
75
+ findNext: function() {return this.find(false);},
76
+ findPrevious: function() {return this.find(true);},
77
+
78
+ find: function(reverse) {
79
+ var self = this, pos = this.cm.clipPos(reverse ? this.pos.from : this.pos.to);
80
+ function savePosAndFail(line) {
81
+ var pos = {line: line, ch: 0};
82
+ self.pos = {from: pos, to: pos};
83
+ self.atOccurrence = false;
84
+ return false;
85
+ }
86
+
87
+ for (;;) {
88
+ if (this.pos = this.matches(reverse, pos)) {
89
+ this.atOccurrence = true;
90
+ return this.pos.match || true;
91
+ }
92
+ if (reverse) {
93
+ if (!pos.line) return savePosAndFail(0);
94
+ pos = {line: pos.line-1, ch: this.cm.getLine(pos.line-1).length};
95
+ }
96
+ else {
97
+ var maxLine = this.cm.lineCount();
98
+ if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
99
+ pos = {line: pos.line+1, ch: 0};
100
+ }
101
+ }
102
+ },
103
+
104
+ from: function() {if (this.atOccurrence) return this.pos.from;},
105
+ to: function() {if (this.atOccurrence) return this.pos.to;},
106
+
107
+ replace: function(newText) {
108
+ var self = this;
109
+ if (this.atOccurrence)
110
+ self.pos.to = this.cm.replaceRange(newText, self.pos.from, self.pos.to);
111
+ }
112
+ };
113
+
114
+ CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
115
+ return new SearchCursor(this, query, pos, caseFold);
116
+ });
117
+ })();
@@ -0,0 +1,16 @@
1
+ .CodeMirror-completions {
2
+ position: absolute;
3
+ z-index: 10;
4
+ overflow: hidden;
5
+ -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
6
+ -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
7
+ box-shadow: 2px 3px 5px rgba(0,0,0,.2);
8
+ }
9
+ .CodeMirror-completions select {
10
+ background: #fafafa;
11
+ outline: none;
12
+ border: none;
13
+ padding: 0;
14
+ margin: 0;
15
+ font-family: monospace;
16
+ }
@@ -0,0 +1,66 @@
1
+ (function() {
2
+ CodeMirror.simpleHint = function(editor, getHints) {
3
+ // We want a single cursor position.
4
+ if (editor.somethingSelected()) return;
5
+ var result = getHints(editor);
6
+ if (!result || !result.list.length) return;
7
+ var completions = result.list;
8
+ function insert(str) {
9
+ editor.replaceRange(str, result.from, result.to);
10
+ }
11
+ // When there is only one completion, use it directly.
12
+ if (completions.length == 1) {insert(completions[0]); return true;}
13
+
14
+ // Build the select widget
15
+ var complete = document.createElement("div");
16
+ complete.className = "CodeMirror-completions";
17
+ var sel = complete.appendChild(document.createElement("select"));
18
+ // Opera doesn't move the selection when pressing up/down in a
19
+ // multi-select, but it does properly support the size property on
20
+ // single-selects, so no multi-select is necessary.
21
+ if (!window.opera) sel.multiple = true;
22
+ for (var i = 0; i < completions.length; ++i) {
23
+ var opt = sel.appendChild(document.createElement("option"));
24
+ opt.appendChild(document.createTextNode(completions[i]));
25
+ }
26
+ sel.firstChild.selected = true;
27
+ sel.size = Math.min(10, completions.length);
28
+ var pos = editor.cursorCoords();
29
+ complete.style.left = pos.x + "px";
30
+ complete.style.top = pos.yBot + "px";
31
+ document.body.appendChild(complete);
32
+ // Hack to hide the scrollbar.
33
+ if (completions.length <= 10)
34
+ complete.style.width = (sel.clientWidth - 1) + "px";
35
+
36
+ var done = false;
37
+ function close() {
38
+ if (done) return;
39
+ done = true;
40
+ complete.parentNode.removeChild(complete);
41
+ }
42
+ function pick() {
43
+ insert(completions[sel.selectedIndex]);
44
+ close();
45
+ setTimeout(function(){editor.focus();}, 50);
46
+ }
47
+ CodeMirror.connect(sel, "blur", close);
48
+ CodeMirror.connect(sel, "keydown", function(event) {
49
+ var code = event.keyCode;
50
+ // Enter
51
+ if (code == 13) {CodeMirror.e_stop(event); pick();}
52
+ // Escape
53
+ else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();}
54
+ else if (code != 38 && code != 40) {
55
+ close(); editor.focus();
56
+ setTimeout(function(){CodeMirror.simpleHint(editor, getHints);}, 50);
57
+ }
58
+ });
59
+ CodeMirror.connect(sel, "dblclick", pick);
60
+
61
+ sel.focus();
62
+ // Opera sometimes ignores focusing a freshly created node
63
+ if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100);
64
+ return true;
65
+ };
66
+ })();
@@ -0,0 +1,249 @@
1
+ CodeMirror.defineMode("clike", function(config, parserConfig) {
2
+ var indentUnit = config.indentUnit,
3
+ keywords = parserConfig.keywords || {},
4
+ blockKeywords = parserConfig.blockKeywords || {},
5
+ atoms = parserConfig.atoms || {},
6
+ hooks = parserConfig.hooks || {},
7
+ multiLineStrings = parserConfig.multiLineStrings;
8
+ var isOperatorChar = /[+\-*&%=<>!?|\/]/;
9
+
10
+ var curPunc;
11
+
12
+ function tokenBase(stream, state) {
13
+ var ch = stream.next();
14
+ if (hooks[ch]) {
15
+ var result = hooks[ch](stream, state);
16
+ if (result !== false) return result;
17
+ }
18
+ if (ch == '"' || ch == "'") {
19
+ state.tokenize = tokenString(ch);
20
+ return state.tokenize(stream, state);
21
+ }
22
+ if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
23
+ curPunc = ch;
24
+ return null
25
+ }
26
+ if (/\d/.test(ch)) {
27
+ stream.eatWhile(/[\w\.]/);
28
+ return "number";
29
+ }
30
+ if (ch == "/") {
31
+ if (stream.eat("*")) {
32
+ state.tokenize = tokenComment;
33
+ return tokenComment(stream, state);
34
+ }
35
+ if (stream.eat("/")) {
36
+ stream.skipToEnd();
37
+ return "comment";
38
+ }
39
+ }
40
+ if (isOperatorChar.test(ch)) {
41
+ stream.eatWhile(isOperatorChar);
42
+ return "operator";
43
+ }
44
+ stream.eatWhile(/[\w\$_]/);
45
+ var cur = stream.current();
46
+ if (keywords.propertyIsEnumerable(cur)) {
47
+ if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
48
+ return "keyword";
49
+ }
50
+ if (atoms.propertyIsEnumerable(cur)) return "atom";
51
+ return "word";
52
+ }
53
+
54
+ function tokenString(quote) {
55
+ return function(stream, state) {
56
+ var escaped = false, next, end = false;
57
+ while ((next = stream.next()) != null) {
58
+ if (next == quote && !escaped) {end = true; break;}
59
+ escaped = !escaped && next == "\\";
60
+ }
61
+ if (end || !(escaped || multiLineStrings))
62
+ state.tokenize = tokenBase;
63
+ return "string";
64
+ };
65
+ }
66
+
67
+ function tokenComment(stream, state) {
68
+ var maybeEnd = false, ch;
69
+ while (ch = stream.next()) {
70
+ if (ch == "/" && maybeEnd) {
71
+ state.tokenize = tokenBase;
72
+ break;
73
+ }
74
+ maybeEnd = (ch == "*");
75
+ }
76
+ return "comment";
77
+ }
78
+
79
+ function Context(indented, column, type, align, prev) {
80
+ this.indented = indented;
81
+ this.column = column;
82
+ this.type = type;
83
+ this.align = align;
84
+ this.prev = prev;
85
+ }
86
+ function pushContext(state, col, type) {
87
+ return state.context = new Context(state.indented, col, type, null, state.context);
88
+ }
89
+ function popContext(state) {
90
+ var t = state.context.type;
91
+ if (t == ")" || t == "]" || t == "}")
92
+ state.indented = state.context.indented;
93
+ return state.context = state.context.prev;
94
+ }
95
+
96
+ // Interface
97
+
98
+ return {
99
+ startState: function(basecolumn) {
100
+ return {
101
+ tokenize: null,
102
+ context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
103
+ indented: 0,
104
+ startOfLine: true
105
+ };
106
+ },
107
+
108
+ token: function(stream, state) {
109
+ var ctx = state.context;
110
+ if (stream.sol()) {
111
+ if (ctx.align == null) ctx.align = false;
112
+ state.indented = stream.indentation();
113
+ state.startOfLine = true;
114
+ }
115
+ if (stream.eatSpace()) return null;
116
+ curPunc = null;
117
+ var style = (state.tokenize || tokenBase)(stream, state);
118
+ if (style == "comment" || style == "meta") return style;
119
+ if (ctx.align == null) ctx.align = true;
120
+
121
+ if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state);
122
+ else if (curPunc == "{") pushContext(state, stream.column(), "}");
123
+ else if (curPunc == "[") pushContext(state, stream.column(), "]");
124
+ else if (curPunc == "(") pushContext(state, stream.column(), ")");
125
+ else if (curPunc == "}") {
126
+ while (ctx.type == "statement") ctx = popContext(state);
127
+ if (ctx.type == "}") ctx = popContext(state);
128
+ while (ctx.type == "statement") ctx = popContext(state);
129
+ }
130
+ else if (curPunc == ctx.type) popContext(state);
131
+ else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement"))
132
+ pushContext(state, stream.column(), "statement");
133
+ state.startOfLine = false;
134
+ return style;
135
+ },
136
+
137
+ indent: function(state, textAfter) {
138
+ if (state.tokenize != tokenBase && state.tokenize != null) return 0;
139
+ var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
140
+ if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
141
+ var closing = firstChar == ctx.type;
142
+ if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit);
143
+ else if (ctx.align) return ctx.column + (closing ? 0 : 1);
144
+ else return ctx.indented + (closing ? 0 : indentUnit);
145
+ },
146
+
147
+ electricChars: "{}"
148
+ };
149
+ });
150
+
151
+ (function() {
152
+ function words(str) {
153
+ var obj = {}, words = str.split(" ");
154
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
155
+ return obj;
156
+ }
157
+ var cKeywords = "auto if break int case long char register continue return default short do sizeof " +
158
+ "double static else struct entry switch extern typedef float union for unsigned " +
159
+ "goto while enum void const signed volatile";
160
+
161
+ function cppHook(stream, state) {
162
+ if (!state.startOfLine) return false;
163
+ stream.skipToEnd();
164
+ return "meta";
165
+ }
166
+
167
+ // C#-style strings where "" escapes a quote.
168
+ function tokenAtString(stream, state) {
169
+ var next;
170
+ while ((next = stream.next()) != null) {
171
+ if (next == '"' && !stream.eat('"')) {
172
+ state.tokenize = null;
173
+ break;
174
+ }
175
+ }
176
+ return "string";
177
+ }
178
+
179
+ CodeMirror.defineMIME("text/x-csrc", {
180
+ name: "clike",
181
+ keywords: words(cKeywords),
182
+ blockKeywords: words("case do else for if switch while struct"),
183
+ atoms: words("null"),
184
+ hooks: {"#": cppHook}
185
+ });
186
+ CodeMirror.defineMIME("text/x-c++src", {
187
+ name: "clike",
188
+ keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " +
189
+ "static_cast typeid catch operator template typename class friend private " +
190
+ "this using const_cast inline public throw virtual delete mutable protected " +
191
+ "wchar_t"),
192
+ blockKeywords: words("catch class do else finally for if struct switch try while"),
193
+ atoms: words("true false null"),
194
+ hooks: {"#": cppHook}
195
+ });
196
+ CodeMirror.defineMIME("text/x-java", {
197
+ name: "clike",
198
+ keywords: words("abstract assert boolean break byte case catch char class const continue default " +
199
+ "do double else enum extends final finally float for goto if implements import " +
200
+ "instanceof int interface long native new package private protected public " +
201
+ "return short static strictfp super switch synchronized this throw throws transient " +
202
+ "try void volatile while"),
203
+ blockKeywords: words("catch class do else finally for if switch try while"),
204
+ atoms: words("true false null"),
205
+ hooks: {
206
+ "@": function(stream, state) {
207
+ stream.eatWhile(/[\w\$_]/);
208
+ return "meta";
209
+ }
210
+ }
211
+ });
212
+ CodeMirror.defineMIME("text/x-csharp", {
213
+ name: "clike",
214
+ keywords: words("abstract as base bool break byte case catch char checked class const continue decimal" +
215
+ " default delegate do double else enum event explicit extern finally fixed float for" +
216
+ " foreach goto if implicit in int interface internal is lock long namespace new object" +
217
+ " operator out override params private protected public readonly ref return sbyte sealed short" +
218
+ " sizeof stackalloc static string struct switch this throw try typeof uint ulong unchecked" +
219
+ " unsafe ushort using virtual void volatile while add alias ascending descending dynamic from get" +
220
+ " global group into join let orderby partial remove select set value var yield"),
221
+ blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
222
+ atoms: words("true false null"),
223
+ hooks: {
224
+ "@": function(stream, state) {
225
+ if (stream.eat('"')) {
226
+ state.tokenize = tokenAtString;
227
+ return tokenAtString(stream, state);
228
+ }
229
+ stream.eatWhile(/[\w\$_]/);
230
+ return "meta";
231
+ }
232
+ }
233
+ });
234
+ CodeMirror.defineMIME("text/x-groovy", {
235
+ name: "clike",
236
+ keywords: words("abstract as assert boolean break byte case catch char class const continue def default " +
237
+ "do double else enum extends final finally float for goto if implements import " +
238
+ "in instanceof int interface long native new package property private protected public " +
239
+ "return short static strictfp super switch synchronized this throw throws transient " +
240
+ "try void volatile while"),
241
+ atoms: words("true false null"),
242
+ hooks: {
243
+ "@": function(stream, state) {
244
+ stream.eatWhile(/[\w\$_]/);
245
+ return "meta";
246
+ }
247
+ }
248
+ });
249
+ }());
@@ -0,0 +1,101 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>CodeMirror: C-like mode</title>
5
+ <link rel="stylesheet" href="../../lib/codemirror.css">
6
+ <script src="../../lib/codemirror.js"></script>
7
+ <script src="clike.js"></script>
8
+ <link rel="stylesheet" href="../../doc/docs.css">
9
+ <style>.CodeMirror {border: 2px inset #dee;}</style>
10
+ </head>
11
+ <body>
12
+ <h1>CodeMirror: C-like mode</h1>
13
+
14
+ <form><textarea id="code" name="code">
15
+ /* C demo code */
16
+
17
+ #include <zmq.h>
18
+ #include <pthread.h>
19
+ #include <semaphore.h>
20
+ #include <time.h>
21
+ #include <stdio.h>
22
+ #include <fcntl.h>
23
+ #include <malloc.h>
24
+
25
+ typedef struct {
26
+ void* arg_socket;
27
+ zmq_msg_t* arg_msg;
28
+ char* arg_string;
29
+ unsigned long arg_len;
30
+ int arg_int, arg_command;
31
+
32
+ int signal_fd;
33
+ int pad;
34
+ void* context;
35
+ sem_t sem;
36
+ } acl_zmq_context;
37
+
38
+ #define p(X) (context->arg_##X)
39
+
40
+ void* zmq_thread(void* context_pointer) {
41
+ acl_zmq_context* context = (acl_zmq_context*)context_pointer;
42
+ char ok = 'K', err = 'X';
43
+ int res;
44
+
45
+ while (1) {
46
+ while ((res = sem_wait(&amp;context->sem)) == EINTR);
47
+ if (res) {write(context->signal_fd, &amp;err, 1); goto cleanup;}
48
+ switch(p(command)) {
49
+ case 0: goto cleanup;
50
+ case 1: p(socket) = zmq_socket(context->context, p(int)); break;
51
+ case 2: p(int) = zmq_close(p(socket)); break;
52
+ case 3: p(int) = zmq_bind(p(socket), p(string)); break;
53
+ case 4: p(int) = zmq_connect(p(socket), p(string)); break;
54
+ case 5: p(int) = zmq_getsockopt(p(socket), p(int), (void*)p(string), &amp;p(len)); break;
55
+ case 6: p(int) = zmq_setsockopt(p(socket), p(int), (void*)p(string), p(len)); break;
56
+ case 7: p(int) = zmq_send(p(socket), p(msg), p(int)); break;
57
+ case 8: p(int) = zmq_recv(p(socket), p(msg), p(int)); break;
58
+ case 9: p(int) = zmq_poll(p(socket), p(int), p(len)); break;
59
+ }
60
+ p(command) = errno;
61
+ write(context->signal_fd, &amp;ok, 1);
62
+ }
63
+ cleanup:
64
+ close(context->signal_fd);
65
+ free(context_pointer);
66
+ return 0;
67
+ }
68
+
69
+ void* zmq_thread_init(void* zmq_context, int signal_fd) {
70
+ acl_zmq_context* context = malloc(sizeof(acl_zmq_context));
71
+ pthread_t thread;
72
+
73
+ context->context = zmq_context;
74
+ context->signal_fd = signal_fd;
75
+ sem_init(&amp;context->sem, 1, 0);
76
+ pthread_create(&amp;thread, 0, &amp;zmq_thread, context);
77
+ pthread_detach(thread);
78
+ return context;
79
+ }
80
+ </textarea></form>
81
+
82
+ <script>
83
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
84
+ lineNumbers: true,
85
+ matchBrackets: true,
86
+ mode: "text/x-csrc"
87
+ });
88
+ </script>
89
+
90
+ <p>Simple mode that tries to handle C-like languages as well as it
91
+ can. Takes two configuration parameters: <code>keywords</code>, an
92
+ object whose property names are the keywords in the language,
93
+ and <code>useCPP</code>, which determines whether C preprocessor
94
+ directives are recognized.</p>
95
+
96
+ <p><strong>MIME types defined:</strong> <code>text/x-csrc</code>
97
+ (C code), <code>text/x-c++src</code> (C++
98
+ code), <code>text/x-java</code> (Java
99
+ code), <code>text/x-groovy</code> (Groovy code).</p>
100
+ </body>
101
+ </html>