diff --git a/lib/ace/mode/clojure.js b/lib/ace/mode/clojure.js index 4af27547..ee44ac3e 100644 --- a/lib/ace/mode/clojure.js +++ b/lib/ace/mode/clojure.js @@ -35,7 +35,6 @@ var oop = require("../lib/oop"); var TextMode = require("./text").Mode; var ClojureHighlightRules = require("./clojure_highlight_rules").ClojureHighlightRules; var MatchingParensOutdent = require("./matching_parens_outdent").MatchingParensOutdent; -var lang = require("../lib/lang"); var Mode = function() { this.HighlightRules = ClojureHighlightRules; @@ -46,40 +45,72 @@ oop.inherits(Mode, TextMode); (function() { this.lineCommentStart = ";"; + this.minorIndentFunctions = ["defn", "defn-", "defmacro", "def", "deftest", "testing"]; - this.$checkBracketDelta = function (line) { + this.$toIndent = function(str) { + return str.split('').map(function(ch) { + if (/\s/.exec(ch)) { + return ch; + } else { + return ' '; + } + }).join(''); + }; + + this.$calculateIndent = function(line, tab) { + var baseIndent = this.$getIndent(line); var delta = 0; - for(var i = 0; i < line.length; i++) { - var ch = line[i]; - if(ch === '(' || ch === '[' || ch === '{') { - delta++; - } else if(ch === ')' || ch === ']' || ch === '}') { + var isParen, ch; + // Walk back from end of line, find matching braces + for (var i = line.length - 1; i >= 0; i--) { + ch = line[i]; + if (ch === '(') { delta--; + isParen = true; + } else if (ch === '(' || ch === '[' || ch === '{') { + delta--; + isParen = false; + } else if (ch === ')' || ch === ']' || ch === '}') { + delta++; + } + if (delta < 0) { + break; } } - return delta; + if (delta < 0 && isParen) { + // Were more brackets opened than closed and was a ( left open? + i += 1; + var iBefore = i; + var fn = ''; + while (true) { + ch = line[i]; + if (ch === ' ' || ch === '\t') { + if(this.minorIndentFunctions.indexOf(fn) !== -1) { + return this.$toIndent(line.substring(0, iBefore - 1) + tab); + } else { + return this.$toIndent(line.substring(0, i + 1)); + } + } else if (ch === undefined) { + return this.$toIndent(line.substring(0, iBefore - 1) + tab); + } + fn += line[i]; + i++; + } + } else if(delta < 0 && !isParen) { + // Were more brackets openend than closed and was it not a (? + return this.$toIndent(line.substring(0, i+1)); + } else if(delta > 0) { + // Mere more brackets closed than opened? Outdent. + baseIndent = baseIndent.substring(0, baseIndent.length - tab.length); + return baseIndent; + } else { + // Were they nicely matched? Just indent like line before. + return baseIndent; + } }; this.getNextLineIndent = function(state, line, tab) { - var indent = this.$getIndent(line); - - var tokenizedLine = this.getTokenizer().getLineTokens(line, state); - var tokens = tokenizedLine.tokens; - - if (tokens.length && tokens[tokens.length-1].type == "comment") { - return indent; - } - - if (state == "start") { - var delta = this.$checkBracketDelta(line); - if (delta > 0) { - indent += tab; - } else if (delta < 0) { - indent = indent.substring(0, indent.length - tab.length); - } - } - - return indent; + return this.$calculateIndent(line, tab); }; this.checkOutdent = function(state, line, input) {