ledger_web 1.2
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.
- data/.gitignore +10 -0
- data/LICENSE +7 -0
- data/README.md +140 -0
- data/Rakefile +11 -0
- data/bin/ledger_web +14 -0
- data/ledger_web.gemspec +26 -0
- data/lib/ledger_web/app.rb +69 -0
- data/lib/ledger_web/config.rb +87 -0
- data/lib/ledger_web/db/migrate/20111226180900_initial_schema.rb +38 -0
- data/lib/ledger_web/db/migrate/20111231132900_add_views.rb +37 -0
- data/lib/ledger_web/db.rb +54 -0
- data/lib/ledger_web/helpers.rb +62 -0
- data/lib/ledger_web/public/bootstrap-dropdown.js +55 -0
- data/lib/ledger_web/public/bootstrap.min.css +356 -0
- data/lib/ledger_web/public/codemirror/keymap/emacs.js +29 -0
- data/lib/ledger_web/public/codemirror/keymap/vim.js +76 -0
- data/lib/ledger_web/public/codemirror/lib/codemirror.css +104 -0
- data/lib/ledger_web/public/codemirror/lib/codemirror.js +2761 -0
- data/lib/ledger_web/public/codemirror/lib/util/dialog.css +23 -0
- data/lib/ledger_web/public/codemirror/lib/util/dialog.js +63 -0
- data/lib/ledger_web/public/codemirror/lib/util/foldcode.js +66 -0
- data/lib/ledger_web/public/codemirror/lib/util/formatting.js +291 -0
- data/lib/ledger_web/public/codemirror/lib/util/javascript-hint.js +83 -0
- data/lib/ledger_web/public/codemirror/lib/util/overlay.js +51 -0
- data/lib/ledger_web/public/codemirror/lib/util/runmode.js +27 -0
- data/lib/ledger_web/public/codemirror/lib/util/search.js +114 -0
- data/lib/ledger_web/public/codemirror/lib/util/searchcursor.js +117 -0
- data/lib/ledger_web/public/codemirror/lib/util/simple-hint.css +16 -0
- data/lib/ledger_web/public/codemirror/lib/util/simple-hint.js +66 -0
- data/lib/ledger_web/public/codemirror/mode/clike/clike.js +249 -0
- data/lib/ledger_web/public/codemirror/mode/clike/index.html +101 -0
- data/lib/ledger_web/public/codemirror/mode/clojure/clojure.js +207 -0
- data/lib/ledger_web/public/codemirror/mode/clojure/index.html +66 -0
- data/lib/ledger_web/public/codemirror/mode/coffeescript/LICENSE +22 -0
- data/lib/ledger_web/public/codemirror/mode/coffeescript/coffeescript.js +325 -0
- data/lib/ledger_web/public/codemirror/mode/coffeescript/index.html +721 -0
- data/lib/ledger_web/public/codemirror/mode/css/css.js +124 -0
- data/lib/ledger_web/public/codemirror/mode/css/index.html +55 -0
- data/lib/ledger_web/public/codemirror/mode/diff/diff.css +3 -0
- data/lib/ledger_web/public/codemirror/mode/diff/diff.js +13 -0
- data/lib/ledger_web/public/codemirror/mode/diff/index.html +99 -0
- data/lib/ledger_web/public/codemirror/mode/gfm/gfm.js +108 -0
- data/lib/ledger_web/public/codemirror/mode/gfm/index.html +47 -0
- data/lib/ledger_web/public/codemirror/mode/groovy/groovy.js +210 -0
- data/lib/ledger_web/public/codemirror/mode/groovy/index.html +71 -0
- data/lib/ledger_web/public/codemirror/mode/haskell/haskell.js +242 -0
- data/lib/ledger_web/public/codemirror/mode/haskell/index.html +60 -0
- data/lib/ledger_web/public/codemirror/mode/htmlembedded/htmlembedded.js +68 -0
- data/lib/ledger_web/public/codemirror/mode/htmlembedded/index.html +49 -0
- data/lib/ledger_web/public/codemirror/mode/htmlmixed/htmlmixed.js +83 -0
- data/lib/ledger_web/public/codemirror/mode/htmlmixed/index.html +51 -0
- data/lib/ledger_web/public/codemirror/mode/javascript/index.html +77 -0
- data/lib/ledger_web/public/codemirror/mode/javascript/javascript.js +360 -0
- data/lib/ledger_web/public/codemirror/mode/jinja2/index.html +37 -0
- data/lib/ledger_web/public/codemirror/mode/jinja2/jinja2.js +42 -0
- data/lib/ledger_web/public/codemirror/mode/lua/index.html +72 -0
- data/lib/ledger_web/public/codemirror/mode/lua/lua.js +140 -0
- data/lib/ledger_web/public/codemirror/mode/markdown/index.html +339 -0
- data/lib/ledger_web/public/codemirror/mode/markdown/markdown.js +242 -0
- data/lib/ledger_web/public/codemirror/mode/ntriples/index.html +32 -0
- data/lib/ledger_web/public/codemirror/mode/ntriples/ntriples.js +172 -0
- data/lib/ledger_web/public/codemirror/mode/pascal/LICENSE +7 -0
- data/lib/ledger_web/public/codemirror/mode/pascal/index.html +48 -0
- data/lib/ledger_web/public/codemirror/mode/pascal/pascal.js +138 -0
- data/lib/ledger_web/public/codemirror/mode/perl/LICENSE +19 -0
- data/lib/ledger_web/public/codemirror/mode/perl/index.html +62 -0
- data/lib/ledger_web/public/codemirror/mode/perl/perl.js +816 -0
- data/lib/ledger_web/public/codemirror/mode/php/index.html +48 -0
- data/lib/ledger_web/public/codemirror/mode/php/php.js +120 -0
- data/lib/ledger_web/public/codemirror/mode/plsql/index.html +62 -0
- data/lib/ledger_web/public/codemirror/mode/plsql/plsql.js +217 -0
- data/lib/ledger_web/public/codemirror/mode/python/LICENSE.txt +21 -0
- data/lib/ledger_web/public/codemirror/mode/python/index.html +122 -0
- data/lib/ledger_web/public/codemirror/mode/python/python.js +333 -0
- data/lib/ledger_web/public/codemirror/mode/r/LICENSE +24 -0
- data/lib/ledger_web/public/codemirror/mode/r/index.html +73 -0
- data/lib/ledger_web/public/codemirror/mode/r/r.js +141 -0
- data/lib/ledger_web/public/codemirror/mode/rpm/changes/changes.js +19 -0
- data/lib/ledger_web/public/codemirror/mode/rpm/changes/index.html +53 -0
- data/lib/ledger_web/public/codemirror/mode/rpm/spec/index.html +99 -0
- data/lib/ledger_web/public/codemirror/mode/rpm/spec/spec.css +5 -0
- data/lib/ledger_web/public/codemirror/mode/rpm/spec/spec.js +66 -0
- data/lib/ledger_web/public/codemirror/mode/rst/index.html +525 -0
- data/lib/ledger_web/public/codemirror/mode/rst/rst.js +326 -0
- data/lib/ledger_web/public/codemirror/mode/ruby/LICENSE +24 -0
- data/lib/ledger_web/public/codemirror/mode/ruby/index.html +171 -0
- data/lib/ledger_web/public/codemirror/mode/ruby/ruby.js +195 -0
- data/lib/ledger_web/public/codemirror/mode/rust/index.html +48 -0
- data/lib/ledger_web/public/codemirror/mode/rust/rust.js +411 -0
- data/lib/ledger_web/public/codemirror/mode/scheme/index.html +64 -0
- data/lib/ledger_web/public/codemirror/mode/scheme/scheme.js +202 -0
- data/lib/ledger_web/public/codemirror/mode/smalltalk/index.html +55 -0
- data/lib/ledger_web/public/codemirror/mode/smalltalk/smalltalk.js +139 -0
- data/lib/ledger_web/public/codemirror/mode/sparql/index.html +40 -0
- data/lib/ledger_web/public/codemirror/mode/sparql/sparql.js +143 -0
- data/lib/ledger_web/public/codemirror/mode/stex/index.html +95 -0
- data/lib/ledger_web/public/codemirror/mode/stex/stex.js +167 -0
- data/lib/ledger_web/public/codemirror/mode/tiddlywiki/index.html +183 -0
- data/lib/ledger_web/public/codemirror/mode/tiddlywiki/tiddlywiki.css +21 -0
- data/lib/ledger_web/public/codemirror/mode/tiddlywiki/tiddlywiki.js +374 -0
- data/lib/ledger_web/public/codemirror/mode/velocity/index.html +103 -0
- data/lib/ledger_web/public/codemirror/mode/velocity/velocity.js +146 -0
- data/lib/ledger_web/public/codemirror/mode/xml/index.html +44 -0
- data/lib/ledger_web/public/codemirror/mode/xml/xml.js +252 -0
- data/lib/ledger_web/public/codemirror/mode/xmlpure/index.html +59 -0
- data/lib/ledger_web/public/codemirror/mode/xmlpure/xmlpure.js +485 -0
- data/lib/ledger_web/public/codemirror/mode/yaml/index.html +67 -0
- data/lib/ledger_web/public/codemirror/mode/yaml/yaml.js +95 -0
- data/lib/ledger_web/public/codemirror/theme/cobalt.css +18 -0
- data/lib/ledger_web/public/codemirror/theme/eclipse.css +25 -0
- data/lib/ledger_web/public/codemirror/theme/elegant.css +10 -0
- data/lib/ledger_web/public/codemirror/theme/monokai.css +28 -0
- data/lib/ledger_web/public/codemirror/theme/neat.css +9 -0
- data/lib/ledger_web/public/codemirror/theme/night.css +21 -0
- data/lib/ledger_web/public/codemirror/theme/rubyblue.css +21 -0
- data/lib/ledger_web/public/jquery-1.7.1.min.js +4 -0
- data/lib/ledger_web/public/jquery.tablesorter.min.js +4 -0
- data/lib/ledger_web/public/ledger.css +14 -0
- data/lib/ledger_web/report.rb +187 -0
- data/lib/ledger_web/reports/savings_rate.erb +49 -0
- data/lib/ledger_web/version.rb +3 -0
- data/lib/ledger_web/views/error.erb +5 -0
- data/lib/ledger_web/views/help.erb +6 -0
- data/lib/ledger_web/views/layout.erb +44 -0
- data/lib/ledger_web/views/table.erb +31 -0
- data/lib/ledger_web/watcher.rb +37 -0
- data/lib/ledger_web.rb +20 -0
- 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(&context->sem)) == EINTR);
|
|
47
|
+
if (res) {write(context->signal_fd, &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), &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, &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(&context->sem, 1, 0);
|
|
76
|
+
pthread_create(&thread, 0, &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>
|