From cbcec10164855f5b71fda23dd3f0aac78a49d24d Mon Sep 17 00:00:00 2001 From: William Candillon Date: Thu, 31 Jan 2013 16:26:27 +0100 Subject: [PATCH] Add XQuery tag completion. --- lib/ace/mode/behaviour/xquery.js | 125 +++++++++++++++++------------ lib/ace/mode/xquery.js | 4 +- lib/ace/mode/xquery/XQueryLexer.js | 4 +- 3 files changed, 77 insertions(+), 56 deletions(-) diff --git a/lib/ace/mode/behaviour/xquery.js b/lib/ace/mode/behaviour/xquery.js index dfe17de7..5df04cd2 100644 --- a/lib/ace/mode/behaviour/xquery.js +++ b/lib/ace/mode/behaviour/xquery.js @@ -1,66 +1,87 @@ -/* -* eXide - web-based XQuery IDE -* -* Copyright (C) 2011 Wolfgang Meier -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Ajax.org B.V. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ define(function(require, exports, module) { "use strict"; var oop = require("../../lib/oop"); var Behaviour = require('../behaviour').Behaviour; var CstyleBehaviour = require('./cstyle').CstyleBehaviour; + var XmlBehaviour = require("../behaviour/xml").XmlBehaviour; + var TokenIterator = require("../../token_iterator").TokenIterator; - var XQueryBehaviour = function (parent) { +function hasType(token, type) { + var hasType = true; + var typeList = token.type.split('.'); + var needleList = type.split('.'); + needleList.forEach(function(needle){ + if (typeList.indexOf(needle) == -1) { + hasType = false; + return false; + } + }); + return hasType; +} + + var XQueryBehaviour = function () { this.inherit(CstyleBehaviour, ["braces", "parens", "string_dquotes"]); // Get string behaviour - this.parent = parent; + this.inherit(XmlBehaviour); // Get xml behaviour -// this.add("brackets", "insertion", function (state, action, editor, session, text) { -// if (text == "\n") { -// var cursor = editor.getCursorPosition(); -// var line = session.doc.getLine(cursor.row); -// var rightChars = line.substring(cursor.column, cursor.column + 2); -// if (rightChars == '') { + var position = editor.getCursorPosition(); + var iterator = new TokenIterator(session, position.row, position.column); + var token = iterator.getCurrentToken(); + var atCursor = false; + if (!token || !hasType(token, 'meta.tag') && !(hasType(token, 'text') && token.value.match('/'))){ + do { + token = iterator.stepBackward(); + } while (token && (hasType(token, 'string') || hasType(token, 'keyword.operator') || hasType(token, 'entity.attribute-name') || hasType(token, 'text'))); + } else { + atCursor = true; + } + if (!token || !hasType(token, 'meta.tag') || iterator.stepBackward().value.match('/')) { + return + } + var tag = token.value.substring(1); + if (atCursor){ + var tag = tag.substring(0, position.column - token.start); + } + + return { + text: '>' + '', + selection: [1, 1] + } + } + }); - // Check for open tag if user enters / and auto-close it. -// this.add("slash", "insertion", function (state, action, editor, session, text) { -// if (text == "/") { -// var cursor = editor.getCursorPosition(); -// var line = session.doc.getLine(cursor.row); -// if (cursor.column > 0 && line.charAt(cursor.column - 1) == "<") { -// line = line.substring(0, cursor.column) + "/" + line.substring(cursor.column); -// var lines = session.doc.getAllLines(); -// lines[cursor.row] = line; -// // call mode helper to close the tag if possible -// parent.exec("closeTag", lines.join(session.doc.getNewLineCharacter()), cursor.row); -// } -// } -// return false; -// }); } oop.inherits(XQueryBehaviour, Behaviour); diff --git a/lib/ace/mode/xquery.js b/lib/ace/mode/xquery.js index 265ec6a5..60022100 100644 --- a/lib/ace/mode/xquery.js +++ b/lib/ace/mode/xquery.js @@ -35,13 +35,13 @@ var oop = require("../lib/oop"); var TextMode = require("./text").Mode; var XQueryLexer = require("./xquery/XQueryLexer").XQueryLexer; var Range = require("../range").Range; -var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; +var XQueryBehaviour = require("./behaviour/xquery").XQueryBehaviour; var CStyleFoldMode = require("./folding/cstyle").FoldMode; var Mode = function(parent) { this.$tokenizer = new XQueryLexer(); - this.$behaviour = new CstyleBehaviour(parent); + this.$behaviour = new XQueryBehaviour(); this.foldingRules = new CStyleFoldMode(); }; diff --git a/lib/ace/mode/xquery/XQueryLexer.js b/lib/ace/mode/xquery/XQueryLexer.js index 2a9ea060..66a807d9 100644 --- a/lib/ace/mode/xquery/XQueryLexer.js +++ b/lib/ace/mode/xquery/XQueryLexer.js @@ -111,11 +111,11 @@ define(function(require, exports, module){ ].concat(ncnames), StartTag: [ { name: "'>'", token: "meta.tag", next: function(stack){ stack.push("TagContent"); } }, - { name: "QName", token: "meta.tag" }, + { name: "QName", token: "entity.other.attribute-name" }, { name: "'='", token: "text" }, { name: "''''", token: "string", next: function(stack){ stack.push("AposAttr"); } }, { name: "'\"'", token: "string", next: function(stack){ stack.push("QuotAttr"); } }, - { name: "'/>'", token: "meta.tag", next: function(stack){ stack.pop(); } } + { name: "'/>'", token: "meta.tag.r", next: function(stack){ stack.pop(); } } ], TagContent: [ { name: "ElementContentChar", token: "text" },