shell.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/LICENSE
  3. ;(function (mod) {
  4. if (typeof exports == 'object' && typeof module == 'object')
  5. // CommonJS
  6. mod(require('../../lib/codemirror'))
  7. else if (typeof define == 'function' && define.amd)
  8. // AMD
  9. define(['../../lib/codemirror'], mod)
  10. // Plain browser env
  11. else mod(CodeMirror)
  12. })(function (CodeMirror) {
  13. 'use strict'
  14. CodeMirror.defineMode('shell', function () {
  15. var words = {}
  16. function define(style, dict) {
  17. for (var i = 0; i < dict.length; i++) {
  18. words[dict[i]] = style
  19. }
  20. }
  21. var commonAtoms = ['true', 'false']
  22. var commonKeywords = ['if', 'then', 'do', 'else', 'elif', 'while', 'until', 'for', 'in', 'esac', 'fi', 'fin', 'fil', 'done', 'exit', 'set', 'unset', 'export', 'function']
  23. var commonCommands = [
  24. 'ab',
  25. 'awk',
  26. 'bash',
  27. 'beep',
  28. 'cat',
  29. 'cc',
  30. 'cd',
  31. 'chown',
  32. 'chmod',
  33. 'chroot',
  34. 'clear',
  35. 'cp',
  36. 'curl',
  37. 'cut',
  38. 'diff',
  39. 'echo',
  40. 'find',
  41. 'gawk',
  42. 'gcc',
  43. 'get',
  44. 'git',
  45. 'grep',
  46. 'hg',
  47. 'kill',
  48. 'killall',
  49. 'ln',
  50. 'ls',
  51. 'make',
  52. 'mkdir',
  53. 'openssl',
  54. 'mv',
  55. 'nc',
  56. 'nl',
  57. 'node',
  58. 'npm',
  59. 'ping',
  60. 'ps',
  61. 'restart',
  62. 'rm',
  63. 'rmdir',
  64. 'sed',
  65. 'service',
  66. 'sh',
  67. 'shopt',
  68. 'shred',
  69. 'source',
  70. 'sort',
  71. 'sleep',
  72. 'ssh',
  73. 'start',
  74. 'stop',
  75. 'su',
  76. 'sudo',
  77. 'svn',
  78. 'tee',
  79. 'telnet',
  80. 'top',
  81. 'touch',
  82. 'vi',
  83. 'vim',
  84. 'wall',
  85. 'wc',
  86. 'wget',
  87. 'who',
  88. 'write',
  89. 'yes',
  90. 'zsh',
  91. ]
  92. CodeMirror.registerHelper('hintWords', 'shell', commonAtoms.concat(commonKeywords, commonCommands))
  93. define('atom', commonAtoms)
  94. define('keyword', commonKeywords)
  95. define('builtin', commonCommands)
  96. function tokenBase(stream, state) {
  97. if (stream.eatSpace()) return null
  98. var sol = stream.sol()
  99. var ch = stream.next()
  100. if (ch === '\\') {
  101. stream.next()
  102. return null
  103. }
  104. if (ch === "'" || ch === '"' || ch === '`') {
  105. state.tokens.unshift(tokenString(ch, ch === '`' ? 'quote' : 'string'))
  106. return tokenize(stream, state)
  107. }
  108. if (ch === '#') {
  109. if (sol && stream.eat('!')) {
  110. stream.skipToEnd()
  111. return 'meta' // 'comment'?
  112. }
  113. stream.skipToEnd()
  114. return 'comment'
  115. }
  116. if (ch === '$') {
  117. state.tokens.unshift(tokenDollar)
  118. return tokenize(stream, state)
  119. }
  120. if (ch === '+' || ch === '=') {
  121. return 'operator'
  122. }
  123. if (ch === '-') {
  124. stream.eat('-')
  125. stream.eatWhile(/\w/)
  126. return 'attribute'
  127. }
  128. if (ch == '<') {
  129. if (stream.match('<<')) return 'operator'
  130. var heredoc = stream.match(/^<-?\s*['"]?([^'"]*)['"]?/)
  131. if (heredoc) {
  132. state.tokens.unshift(tokenHeredoc(heredoc[1]))
  133. return 'string-2'
  134. }
  135. }
  136. if (/\d/.test(ch)) {
  137. stream.eatWhile(/\d/)
  138. if (stream.eol() || !/\w/.test(stream.peek())) {
  139. return 'number'
  140. }
  141. }
  142. stream.eatWhile(/[\w-]/)
  143. var cur = stream.current()
  144. if (stream.peek() === '=' && /\w+/.test(cur)) return 'def'
  145. return words.hasOwnProperty(cur) ? words[cur] : null
  146. }
  147. function tokenString(quote, style) {
  148. var close = quote == '(' ? ')' : quote == '{' ? '}' : quote
  149. return function (stream, state) {
  150. var next,
  151. escaped = false
  152. while ((next = stream.next()) != null) {
  153. if (next === close && !escaped) {
  154. state.tokens.shift()
  155. break
  156. } else if (next === '$' && !escaped && quote !== "'" && stream.peek() != close) {
  157. escaped = true
  158. stream.backUp(1)
  159. state.tokens.unshift(tokenDollar)
  160. break
  161. } else if (!escaped && quote !== close && next === quote) {
  162. state.tokens.unshift(tokenString(quote, style))
  163. return tokenize(stream, state)
  164. } else if (!escaped && /['"]/.test(next) && !/['"]/.test(quote)) {
  165. state.tokens.unshift(tokenStringStart(next, 'string'))
  166. stream.backUp(1)
  167. break
  168. }
  169. escaped = !escaped && next === '\\'
  170. }
  171. return style
  172. }
  173. }
  174. function tokenStringStart(quote, style) {
  175. return function (stream, state) {
  176. state.tokens[0] = tokenString(quote, style)
  177. stream.next()
  178. return tokenize(stream, state)
  179. }
  180. }
  181. var tokenDollar = function (stream, state) {
  182. if (state.tokens.length > 1) stream.eat('$')
  183. var ch = stream.next()
  184. if (/['"({]/.test(ch)) {
  185. state.tokens[0] = tokenString(ch, ch == '(' ? 'quote' : ch == '{' ? 'def' : 'string')
  186. return tokenize(stream, state)
  187. }
  188. if (!/\d/.test(ch)) stream.eatWhile(/\w/)
  189. state.tokens.shift()
  190. return 'def'
  191. }
  192. function tokenHeredoc(delim) {
  193. return function (stream, state) {
  194. if (stream.sol() && stream.string == delim) state.tokens.shift()
  195. stream.skipToEnd()
  196. return 'string-2'
  197. }
  198. }
  199. function tokenize(stream, state) {
  200. return (state.tokens[0] || tokenBase)(stream, state)
  201. }
  202. return {
  203. startState: function () {
  204. return { tokens: [] }
  205. },
  206. token: function (stream, state) {
  207. return tokenize(stream, state)
  208. },
  209. closeBrackets: '()[]{}\'\'""``',
  210. lineComment: '#',
  211. fold: 'brace',
  212. }
  213. })
  214. CodeMirror.defineMIME('text/x-sh', 'shell')
  215. // Apache uses a slightly different Media Type for Shell scripts
  216. // http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
  217. CodeMirror.defineMIME('application/x-sh', 'shell')
  218. })