// 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); else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { "use strict"; CodeMirror.defineMode('shell', function() { var words = {}; function define(style, dict) { for (var i = 0; i < dict.length; i++) { words[dict[i]] = style; } }; var commonAtoms = ["true", "false"]; var commonKeywords = ["if", "then", "do", "else", "elif", "while", "until", "for", "in", "esac", "fi", "fin", "fil", "done", "exit", "set", "unset", "export", "function" ]; var commonCommands = 'ab|awk|bash|beep|cat|cc|cd|chown|chmod|chroot|clear|cp|curl|cut|diff|echo|find|gawk|gcc|get|git|grep|hg|kill|killall|ln|ls|make|mkdir|openssl|mv|nc|nl|node|npm|ping|ps|restart|rm|rmdir|sed|service|sh|shopt|shred|source|sort|sleep|ssh|start|stop|su|sudo|svn|tee|telnet|top|touch|vi|vim|wall|wc|wget|who|write|yes|zsh'.split("|") function shellHint(editor, options) { var cur = editor.getCursor(), token = editor.getTokenAt(cur); if (token.string == "") return // 关键字提示 var hints = commonAtoms.concat(commonKeywords, commonCommands) var localCommands = JSON.parse(localStorage['shellCommands']).filter(x => !hints.includes(x)) hints = hints.concat(localCommands).filter(x => x.slice(0, token.string.length) == token.string) // 特殊变量提示 var specialVars = localStorage['specialVars'] if (specialVars) specialVars.split(',').forEach(s => { if (s.toUpperCase().slice(2, token.string.length + 2) == token.string.toUpperCase()) hints.push(s) }) // 本地单词提示 var anyword = CodeMirror.hint.anyword(editor, options).list anyword.forEach(a => { if (!hints.includes(a)) hints.push(a) }) return { list: hints, from: CodeMirror.Pos(cur.line, token.start), to: CodeMirror.Pos(cur.line, token.end) }; } CodeMirror.registerHelper("hint", "shell", shellHint); define('atom', commonAtoms); define('keyword', commonKeywords); define('builtin', commonCommands); function tokenBase(stream, state) { if (stream.eatSpace()) return null; var sol = stream.sol(); var ch = stream.next(); if (ch === '\\') { stream.next(); return null; } if (ch === '\'' || ch === '"' || ch === '`') { state.tokens.unshift(tokenString(ch, ch === "`" ? "quote" : "string")); return tokenize(stream, state); } if (ch === '#') { if (sol && stream.eat('!')) { stream.skipToEnd(); return 'meta'; // 'comment'? } stream.skipToEnd(); return 'comment'; } if (ch === '$') { state.tokens.unshift(tokenDollar); return tokenize(stream, state); } if (ch === '+' || ch === '=') { return 'operator'; } if (ch === '-') { stream.eat('-'); stream.eatWhile(/\w/); return 'attribute'; } if (/^[0-9\.]/.test(ch)) { stream.eatWhile(/\d/); if (stream.eol() || !/\w/.test(stream.peek())) { return 'number'; } } stream.eatWhile(/[\w-]/); var cur = stream.current(); if (stream.peek() === '=' && /\w+/.test(cur)) return 'def'; return words.hasOwnProperty(cur) ? words[cur] : null; } function tokenString(quote, style) { var close = quote == "(" ? ")" : quote == "{" ? "}" : quote return function(stream, state) { var next, escaped = false; while ((next = stream.next()) != null) { if (next === close && !escaped) { state.tokens.shift(); break; } else if (next === '$' && !escaped && quote !== "'" && stream.peek() != close) { escaped = true; stream.backUp(1); state.tokens.unshift(tokenDollar); break; } else if (!escaped && quote !== close && next === quote) { state.tokens.unshift(tokenString(quote, style)) return tokenize(stream, state) } else if (!escaped && /['"]/.test(next) && !/['"]/.test(quote)) { state.tokens.unshift(tokenStringStart(next, "string")); stream.backUp(1); break; } escaped = !escaped && next === '\\'; } return style; }; }; function tokenStringStart(quote, style) { return function(stream, state) { state.tokens[0] = tokenString(quote, style) stream.next() return tokenize(stream, state) } } var tokenDollar = function(stream, state) { if (state.tokens.length > 1) stream.eat('$'); var ch = stream.next() if (/['"({]/.test(ch)) { state.tokens[0] = tokenString(ch, ch == "(" ? "quote" : ch == "{" ? "def" : "string"); return tokenize(stream, state); } if (!/\d/.test(ch)) stream.eatWhile(/\w/); state.tokens.shift(); return 'def'; }; function tokenize(stream, state) { return (state.tokens[0] || tokenBase)(stream, state); }; return { startState: function() { return { tokens: [] }; }, token: function(stream, state) { return tokenize(stream, state); }, closeBrackets: "()[]{}''\"\"``", lineComment: '#', fold: "brace" }; }); CodeMirror.defineMIME('text/x-sh', 'shell'); // Apache uses a slightly different Media Type for Shell scripts // http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types CodeMirror.defineMIME('application/x-sh', 'shell'); });