123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- // CodeMirror, copyright (c) by Marijn Haverbeke and others
- // Distributed under an MIT license: https://codemirror.net/LICENSE
- ;(function (mod) {
- if (typeof exports == 'object' && typeof module == 'object')
- // CommonJS
- mod(require('../../lib/codemirror'))
- else if (typeof define == 'function' && define.amd)
- // AMD
- define(['../../lib/codemirror'], mod)
- // Plain browser env
- else mod(CodeMirror)
- })(function (CodeMirror) {
- 'use strict'
- var Pos = CodeMirror.Pos
- function matches(hint, typed, matchInMiddle) {
- if (matchInMiddle) return hint.indexOf(typed) >= 0
- else return hint.lastIndexOf(typed, 0) == 0
- }
- function getHints(cm, options) {
- var tags = options && options.schemaInfo
- var quote = (options && options.quoteChar) || '"'
- var matchInMiddle = options && options.matchInMiddle
- if (!tags) return
- var cur = cm.getCursor(),
- token = cm.getTokenAt(cur)
- if (token.end > cur.ch) {
- token.end = cur.ch
- token.string = token.string.slice(0, cur.ch - token.start)
- }
- var inner = CodeMirror.innerMode(cm.getMode(), token.state)
- if (!inner.mode.xmlCurrentTag) return
- var result = [],
- replaceToken = false,
- prefix
- var tag = /\btag\b/.test(token.type) && !/>$/.test(token.string)
- var tagName = tag && /^\w/.test(token.string),
- tagStart
- if (tagName) {
- var before = cm.getLine(cur.line).slice(Math.max(0, token.start - 2), token.start)
- var tagType = /<\/$/.test(before) ? 'close' : /<$/.test(before) ? 'open' : null
- if (tagType) tagStart = token.start - (tagType == 'close' ? 2 : 1)
- } else if (tag && token.string == '<') {
- tagType = 'open'
- } else if (tag && token.string == '</') {
- tagType = 'close'
- }
- var tagInfo = inner.mode.xmlCurrentTag(inner.state)
- if ((!tag && !tagInfo) || tagType) {
- if (tagName) prefix = token.string
- replaceToken = tagType
- var context = inner.mode.xmlCurrentContext ? inner.mode.xmlCurrentContext(inner.state) : []
- var inner = context.length && context[context.length - 1]
- var curTag = inner && tags[inner]
- var childList = inner ? curTag && curTag.children : tags['!top']
- if (childList && tagType != 'close') {
- for (var i = 0; i < childList.length; ++i) if (!prefix || matches(childList[i], prefix, matchInMiddle)) result.push('<' + childList[i])
- } else if (tagType != 'close') {
- for (var name in tags) if (tags.hasOwnProperty(name) && name != '!top' && name != '!attrs' && (!prefix || matches(name, prefix, matchInMiddle))) result.push('<' + name)
- }
- if (inner && (!prefix || (tagType == 'close' && matches(inner, prefix, matchInMiddle)))) result.push('</' + inner + '>')
- } else {
- // Attribute completion
- var curTag = tagInfo && tags[tagInfo.name],
- attrs = curTag && curTag.attrs
- var globalAttrs = tags['!attrs']
- if (!attrs && !globalAttrs) return
- if (!attrs) {
- attrs = globalAttrs
- } else if (globalAttrs) {
- // Combine tag-local and global attributes
- var set = {}
- for (var nm in globalAttrs) if (globalAttrs.hasOwnProperty(nm)) set[nm] = globalAttrs[nm]
- for (var nm in attrs) if (attrs.hasOwnProperty(nm)) set[nm] = attrs[nm]
- attrs = set
- }
- if (token.type == 'string' || token.string == '=') {
- // A value
- var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)), Pos(cur.line, token.type == 'string' ? token.start : token.end))
- var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/),
- atValues
- if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return
- if (typeof atValues == 'function') atValues = atValues.call(this, cm) // Functions can be used to supply values for autocomplete widget
- if (token.type == 'string') {
- prefix = token.string
- var n = 0
- if (/['"]/.test(token.string.charAt(0))) {
- quote = token.string.charAt(0)
- prefix = token.string.slice(1)
- n++
- }
- var len = token.string.length
- if (/['"]/.test(token.string.charAt(len - 1))) {
- quote = token.string.charAt(len - 1)
- prefix = token.string.substr(n, len - 2)
- }
- if (n) {
- // an opening quote
- var line = cm.getLine(cur.line)
- if (line.length > token.end && line.charAt(token.end) == quote) token.end++ // include a closing quote
- }
- replaceToken = true
- }
- var returnHintsFromAtValues = function (atValues) {
- if (atValues) for (var i = 0; i < atValues.length; ++i) if (!prefix || matches(atValues[i], prefix, matchInMiddle)) result.push(quote + atValues[i] + quote)
- return returnHints()
- }
- if (atValues && atValues.then) return atValues.then(returnHintsFromAtValues)
- return returnHintsFromAtValues(atValues)
- } else {
- // An attribute name
- if (token.type == 'attribute') {
- prefix = token.string
- replaceToken = true
- }
- for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || matches(attr, prefix, matchInMiddle))) result.push(attr)
- }
- }
- function returnHints() {
- return {
- list: result,
- from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur,
- to: replaceToken ? Pos(cur.line, token.end) : cur,
- }
- }
- return returnHints()
- }
- CodeMirror.registerHelper('hint', 'xml', getHints)
- })
|