diff --git a/scripts/bundle.js b/scripts/bundle.js index 9b079c36..fe87ee3d 100644 --- a/scripts/bundle.js +++ b/scripts/bundle.js @@ -63,6 +63,7 @@ bundleOne('redis/redis'); bundleOne('csp/csp'); bundleOne('scheme/scheme'); bundleOne('clojure/clojure'); +bundleOne('shell/shell'); function bundleOne(moduleId, exclude) { requirejs.optimize({ @@ -74,7 +75,7 @@ function bundleOne(moduleId, exclude) { 'vs/basic-languages': REPO_ROOT + '/release/dev' }, optimize: 'none' - }, function(buildResponse) { + }, function (buildResponse) { const filePath = path.join(REPO_ROOT, 'release/min/' + moduleId + '.js'); const fileContents = fs.readFileSync(filePath).toString(); console.log(); diff --git a/src/monaco.contribution.ts b/src/monaco.contribution.ts index 691fab63..0342ec3e 100644 --- a/src/monaco.contribution.ts +++ b/src/monaco.contribution.ts @@ -46,3 +46,4 @@ import './xml/xml.contribution'; import './yaml/yaml.contribution'; import './scheme/scheme.contribution'; import './clojure/clojure.contribution'; +import './shell/shell.contribution'; diff --git a/src/shell/shell.contribution.ts b/src/shell/shell.contribution.ts new file mode 100644 index 00000000..a73f71bc --- /dev/null +++ b/src/shell/shell.contribution.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the MIT License. See License.txt in the project root for license information. +*--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { registerLanguage } from '../_.contribution'; + +// Allow for running under nodejs/requirejs in tests +const _monaco: typeof monaco = + typeof monaco === 'undefined' ? (self).monaco : monaco; + +registerLanguage({ + id: 'shell', + extensions: ['.sh', '.bash'], + aliases: ['Shell', 'sh'], + loader: () => _monaco.Promise.wrap(import('./shell')), +}); diff --git a/src/shell/shell.test.ts b/src/shell/shell.test.ts new file mode 100644 index 00000000..c34e3b9e --- /dev/null +++ b/src/shell/shell.test.ts @@ -0,0 +1,282 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { testTokenization } from '../test/testRunner'; + +testTokenization('shell', [ + // Keywords + [{ + line: 'if while', + tokens: [ + { startIndex: 0, type: 'keyword.shell' }, + { startIndex: 2, type: 'white.shell' }, + { startIndex: 3, type: 'keyword.shell' } + ] + }], + + // Predefined & attribute + [{ + line: 'ps -aux | grep code', + tokens: [ + { startIndex: 0, type: 'type.identifier.shell' }, + { startIndex: 2, type: 'white.shell' }, + { startIndex: 3, type: 'attribute.name.shell' }, + { startIndex: 7, type: 'white.shell' }, + { startIndex: 8, type: 'delimiter.shell' }, + { startIndex: 9, type: 'white.shell' }, + { startIndex: 10, type: 'type.identifier.shell' }, + { startIndex: 14, type: 'white.shell' }, + { startIndex: 15, type: '' }, + ] + }], + + [{ + line: '# comment', + tokens: [ + { startIndex: 0, type: 'comment.shell' } + ] + }, { + line: 'cd tree', + tokens: [ + { startIndex: 0, type: 'type.identifier.shell' }, + { startIndex: 2, type: 'white.shell' }, + { startIndex: 3, type: '' } + ] + }], + + // Shebang + [{ + line: '#!/bin/env bash', + tokens: [ + { startIndex: 0, type: 'metatag.shell' } + ] + }], + + // Comments + [{ + line: '#', + tokens: [ + { startIndex: 0, type: 'comment.shell' } + ] + }], + + [{ + line: '# a comment', + tokens: [ + { startIndex: 0, type: 'comment.shell' } + ] + }], + + [{ + line: ' # a comment', + tokens: [ + { startIndex: 0, type: 'white.shell' }, + { startIndex: 4, type: 'comment.shell' } + ] + }], + + // numbers + [{ + line: '0', + tokens: [ + { startIndex: 0, type: 'number.shell' } + ] + }], + + [{ + line: '0.0', + tokens: [ + { startIndex: 0, type: 'number.float.shell' } + ] + }], + + [{ + line: '0x123', + tokens: [ + { startIndex: 0, type: 'number.hex.shell' } + ] + }], + + [{ + line: '23.5', + tokens: [ + { startIndex: 0, type: 'number.float.shell' } + ] + }], + + [{ + line: '23.5e3', + tokens: [ + { startIndex: 0, type: 'number.float.shell' } + ] + }], + + [{ + line: '23.5E3', + tokens: [ + { startIndex: 0, type: 'number.float.shell' } + ] + }], + + [{ + line: '1.72e-3', + tokens: [ + { startIndex: 0, type: 'number.float.shell' } + ] + }], + + [{ + line: '0+0', + tokens: [ + { startIndex: 0, type: 'number.shell' }, + { startIndex: 1, type: 'delimiter.shell' }, + { startIndex: 2, type: 'number.shell' } + ] + }], + + [{ + line: '100+10', + tokens: [ + { startIndex: 0, type: 'number.shell' }, + { startIndex: 3, type: 'delimiter.shell' }, + { startIndex: 4, type: 'number.shell' } + ] + }], + + [{ + line: '0 + 0', + tokens: [ + { startIndex: 0, type: 'number.shell' }, + { startIndex: 1, type: 'white.shell' }, + { startIndex: 2, type: 'delimiter.shell' }, + { startIndex: 3, type: 'white.shell' }, + { startIndex: 4, type: 'number.shell' } + ] + }], + + // Strings + [{ + line: "'test string'", + tokens: [ + { startIndex: 0, type: 'string.shell' } + ] + }], + + [{ + line: '"test string"', + tokens: [ + { startIndex: 0, type: 'string.shell' } + ] + }], + + [{ + line: "'test", + tokens: [ + { startIndex: 0, type: 'string.shell' } + ], + }, { + line: '', + tokens: [ + + ] + }, { + line: "string'", + tokens: [ + { startIndex: 0, type: 'string.shell' } + ] + }], + + [{ + line: '"test', + tokens: [ + { startIndex: 0, type: 'string.shell' } + ], + }, { + line: '', + tokens: [ + + ] + }, { + line: 'string"', + tokens: [ + { startIndex: 0, type: 'string.shell' } + ] + }], + + // Parameters + [{ + line: '$1', + tokens: [ + { startIndex: 0, type: 'variable.predefined.shell' } + ] + }], + + [{ + line: '$a', + tokens: [ + { startIndex: 0, type: 'variable.shell' } + ] + }], + + [{ + line: '${string:position}', + tokens: [ + { startIndex: 0, type: 'variable.shell' }, + { startIndex: 8, type: 'delimiter.shell' }, + { startIndex: 9, type: 'variable.shell' } + ] + }], + + [{ + line: '$(pwd)', + tokens: [ + { startIndex: 0, type: 'variable.shell' }, + ] + }], + + [{ + line: 'echo $hello | less', + tokens: [ + { startIndex: 0, type: 'type.identifier.shell' }, + { startIndex: 4, type: 'white.shell' }, + { startIndex: 5, type: 'variable.shell' }, + { startIndex: 11, type: 'white.shell' }, + { startIndex: 12, type: 'delimiter.shell' }, + { startIndex: 13, type: 'white.shell' }, + { startIndex: 14, type: '' } + ] + }], + + // HereDoc + [{ + line: '<< word', + tokens: [ + { startIndex: 0, type: 'constants.shell' }, + { startIndex: 2, type: 'white.shell' }, + { startIndex: 3, type: 'string.heredoc.shell' } + ] + }], + + [{ + line: '<<- "word"', + tokens: [ + { startIndex: 0, type: 'constants.shell' }, + { startIndex: 3, type: 'white.shell' }, + { startIndex: 4, type: 'string.heredoc.delimiter.shell' }, + { startIndex: 5, type: 'string.heredoc.shell' }, + { startIndex: 9, type: 'string.heredoc.delimiter.shell' }, + ] + }], + + [{ + line: '<<< word', + tokens: [ + { startIndex: 0, type: 'constants.shell' }, + { startIndex: 3, type: 'white.shell' }, + { startIndex: 4, type: 'string.heredoc.shell' } + ] + }], +]) diff --git a/src/shell/shell.ts b/src/shell/shell.ts new file mode 100644 index 00000000..03c6197f --- /dev/null +++ b/src/shell/shell.ts @@ -0,0 +1,213 @@ +/*--------------------------------------------------------------------------------------------- +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the MIT License. See License.txt in the project root for license information. +*--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import IRichLanguageConfiguration = monaco.languages.LanguageConfiguration; +import ILanguage = monaco.languages.IMonarchLanguage; + +export const conf: IRichLanguageConfiguration = { + comments: { + lineComment: '#', + }, + brackets: [['{', '}'], ['[', ']'], ['(', ')']], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: "'", close: "'" }, + { open: '`', close: '`' }, + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: "'", close: "'" }, + { open: '`', close: '`' }, + ], +}; + +export const language = { + defaultToken: '', + ignoreCase: true, + tokenPostfix: '.shell', + + brackets: [ + { token: 'delimiter.bracket', open: '{', close: '}' }, + { token: 'delimiter.parenthesis', open: '(', close: ')' }, + { token: 'delimiter.square', open: '[', close: ']' }, + ], + + keywords: [ + 'if', + 'then', + 'do', + 'else', + 'elif', + 'while', + 'until', + 'for', + 'in', + 'esac', + 'fi', + 'fin', + 'fil', + 'done', + 'exit', + 'set', + 'unset', + 'export', + 'function', + ], + + builtins: [ + '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', + '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', + ], + + // we include these common regular expressions + symbols: /[=>