├── .gitignore ├── doc ├── 2022-06-18-02-33-59.png ├── 2022-06-18-02-36-00.png ├── 2022-06-18-02-38-09.png └── 2022-06-18-02-40-22.png ├── .vscodeignore ├── .vscode ├── extensions.json ├── tasks.json ├── settings.json └── launch.json ├── src ├── test │ ├── suite │ │ ├── extension.test.ts │ │ └── index.ts │ └── runTest.ts └── extension.ts ├── tsconfig.json ├── .eslintrc.json ├── LICENSE ├── README.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | node_modules 4 | .vscode-test/ 5 | *.vsix 6 | -------------------------------------------------------------------------------- /doc/2022-06-18-02-33-59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ko1/vscode-ruby-rstfilter/HEAD/doc/2022-06-18-02-33-59.png -------------------------------------------------------------------------------- /doc/2022-06-18-02-36-00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ko1/vscode-ruby-rstfilter/HEAD/doc/2022-06-18-02-36-00.png -------------------------------------------------------------------------------- /doc/2022-06-18-02-38-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ko1/vscode-ruby-rstfilter/HEAD/doc/2022-06-18-02-38-09.png -------------------------------------------------------------------------------- /doc/2022-06-18-02-40-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ko1/vscode-ruby-rstfilter/HEAD/doc/2022-06-18-02-40-22.png -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | src/** 4 | .gitignore 5 | .yarnrc 6 | vsc-extension-quickstart.md 7 | **/tsconfig.json 8 | **/.eslintrc.json 9 | **/*.map 10 | **/*.ts 11 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../../extension'; 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.strictEqual(-1, [1, 2, 3].indexOf(5)); 13 | assert.strictEqual(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2020", 5 | "outDir": "out", 6 | "lib": [ 7 | "ES2020" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/naming-convention": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off" 18 | }, 19 | "ignorePatterns": [ 20 | "out", 21 | "dist", 22 | "**/*.d.ts" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from '@vscode/test-electron'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/out/**/*.js" 17 | ], 18 | "preLaunchTask": "${defaultBuildTask}" 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "args": [ 25 | "--extensionDevelopmentPath=${workspaceFolder}", 26 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 27 | ], 28 | "outFiles": [ 29 | "${workspaceFolder}/out/test/**/*.js" 30 | ], 31 | "preLaunchTask": "${defaultBuildTask}" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Koichi Sasada 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vscode-rstfilter README 2 | 3 | You can see the execution results by saving the file. 4 | 5 | ## Requirements 6 | 7 | `rstfilter-lsp` command in latest `rstfilter` gem is needed. 8 | 9 | ``` 10 | $ gem install rstfilter 11 | ``` 12 | 13 | ## Usage 14 | 15 | 1. *Open* `.rb` file and *edit* the script. 16 | 2. *Start* rstfilter using one of the following three methods: 17 | * Use shortcut `Ctrl+Alt+S`. (recommended) 18 | * Use command "rstfilter: Save, exec and show results". 19 | 20 | ![Command Palette](doc/2022-06-18-02-40-22.png) 21 | 22 | * Click "rstfilter" status bar. 23 | 24 | ![Status Bar](doc/2022-06-18-02-33-59.png) 25 | 26 | 3. *Confirm* the execution results on source code and the output. 27 | 28 | ![Output](doc/2022-06-18-02-36-00.png) 29 | 30 | 4. *Hover* your mouse pointer on the expression in the editor window and you can see the results. 31 | 32 | ![Hover](doc/2022-06-18-02-38-09.png) 33 | 34 | 5. *Edit* the script and all results are removed. 35 | 36 | If your program halts, click the rstfilter status bar and the Ruby process will be killed. 37 | 38 | ## Commands 39 | 40 | * `ruby-rstfilter.save_exec_and_show`: Start rstfilter. 41 | * `ruby-rstfilter.restart`: Restart rstfilter language server. If a Ruby process is running by rstfilter, kill the Ruby process. 42 | 43 | ## Extension Settings 44 | 45 | * Rstfilter Lsp Path: Path to rstfilter-lsp (gem rstfilter for install). 46 | * Enable On Default: Enable rstfilter extension on load. 47 | 48 | ## Advise 49 | 50 | ### Writing library tips 51 | 52 | Traditional idiom using `$0` will help to use this extension. 53 | 54 | ```ruby 55 | class MyLib 56 | # ... 57 | end 58 | 59 | if $0 == __FILE__ 60 | # Try MyLib here. 61 | # This code doesn't work when this file is required. 62 | end 63 | ``` 64 | 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ruby-rstfilter", 3 | "displayName": "Ruby's rstfilter extension", 4 | "description": "Show the Ruby's execution results in your source code.", 5 | "publisher": "KoichiSasada", 6 | "version": "0.0.4", 7 | "license": "MIT", 8 | "author": { 9 | "name": "Koichi Sasada", 10 | "email": "ko1@atdot.net", 11 | "url": "https://www.atdot.net/~ko1/" 12 | }, 13 | "homepage": "https://github.com/ko1/vscode-ruby-rstfilter", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/ko1/vscode-ruby-rstfilter.git" 17 | }, 18 | "bugs": { 19 | "url": "https://github.com/ko1/vscode-ruby-rstfilter/issues" 20 | }, 21 | "categories": [ 22 | "Other" 23 | ], 24 | "activationEvents": [ 25 | "onLanguage:ruby" 26 | ], 27 | "main": "./out/extension.js", 28 | "contributes": { 29 | "configuration": { 30 | "title": "ruby-rstfilter", 31 | "properties": { 32 | "ruby-rstfilter.rstfilterLspPath": { 33 | "type": "string", 34 | "default": "rstfilter-lsp", 35 | "description": "Path to rstfilter-lsp (gem rstfilter for install)" 36 | } 37 | } 38 | }, 39 | "commands": [ 40 | { 41 | "command": "ruby-rstfilter.restart", 42 | "title": "Restart ruby-rstfilter", 43 | "category": "rstfilter" 44 | }, 45 | { 46 | "command": "ruby-rstfilter.save_exec_and_show", 47 | "title": "Save, exec and show the execution results", 48 | "category": "rstfilter" 49 | } 50 | ], 51 | "keybindings": [ 52 | { 53 | "command": "ruby-rstfilter.save_exec_and_show", 54 | "key": "ctrl+alt+s", 55 | "mac": "cmd+ctrl+s", 56 | "when": "editorTextFocus" 57 | } 58 | ] 59 | 60 | }, 61 | "scripts": { 62 | "vscode:prepublish": "npm run compile", 63 | "compile": "tsc -p ./", 64 | "watch": "tsc -watch -p ./", 65 | "pretest": "npm run compile && npm run lint", 66 | "lint": "eslint src --ext ts", 67 | "test": "node ./out/test/runTest.js" 68 | }, 69 | "devDependencies": { 70 | "@types/vscode": "^1.67.0", 71 | "@types/glob": "^7.2.0", 72 | "@types/mocha": "^9.1.1", 73 | "@types/node": "14.x", 74 | "@typescript-eslint/eslint-plugin": "^5.21.0", 75 | "@typescript-eslint/parser": "^5.21.0", 76 | "eslint": "^8.14.0", 77 | "glob": "^8.0.1", 78 | "mocha": "^9.2.2", 79 | "typescript": "^4.6.4", 80 | "@vscode/test-electron": "^2.1.3" 81 | }, 82 | 83 | "engines": { 84 | "vscode": "^1.67.0" 85 | }, 86 | "dependencies": { 87 | "vscode-languageclient": "^8.0.1" 88 | } 89 | } 90 | 91 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | // The module 'vscode' contains the VS Code extensibility API 2 | // Import the module and reference it with the alias vscode in your code below 3 | import { stat } from 'fs'; 4 | import * as vscode from 'vscode'; 5 | import { 6 | LanguageClient, 7 | LanguageClientOptions, 8 | ServerOptions 9 | } from 'vscode-languageclient/node'; 10 | 11 | // this method is called when your extension is activated 12 | // your extension is activated the very first time the command is executed 13 | export function activate(context: vscode.ExtensionContext) { 14 | context.subscriptions.push(vscode.commands.registerCommand("ruby-rstfilter.restart", () => { 15 | if (client) { 16 | stopClient(); 17 | } 18 | startClient(); 19 | })); 20 | 21 | context.subscriptions.push(vscode.commands.registerCommand("ruby-rstfilter.save_exec_and_show", async () => { 22 | if (!client) { 23 | client = startClient(); 24 | } 25 | 26 | const editor = vscode.window.activeTextEditor; 27 | 28 | if (editor) { 29 | await editor.document.save(); 30 | 31 | if (client && editor.document.languageId == "ruby") { 32 | client.sendNotification("rstfilter/start", { 33 | path: editor.document.uri.path 34 | }); 35 | } 36 | } 37 | })); 38 | 39 | startClient(); 40 | } 41 | 42 | // this method is called when your extension is deactivated 43 | export function deactivate() { 44 | stopClient(); 45 | } 46 | 47 | // control client 48 | 49 | let client: LanguageClient | undefined; 50 | let statusBar: vscode.StatusBarItem; 51 | let rstfilterVersion: string; 52 | let rstfilterOutput: vscode.OutputChannel; 53 | 54 | function enableStatus() { 55 | statusBar.text = "rstfilter"; 56 | statusBar.tooltip = `rstfilter is enabled (${rstfilterVersion}).`; 57 | statusBar.command = "ruby-rstfilter.save_exec_and_show"; 58 | statusBar.show(); 59 | } 60 | 61 | function runningStauts(target: string) { 62 | statusBar.text = "$(sync~spin) rstfilter"; 63 | statusBar.tooltip = `target: ${target}`; 64 | statusBar.command = "ruby-rstfilter.restart"; 65 | } 66 | 67 | function deleteStatus() { 68 | statusBar.hide(); 69 | statusBar.dispose(); 70 | } 71 | 72 | function startClient(): LanguageClient { 73 | statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right); 74 | statusBar.text = "$(sync~spin) rstfilter"; // loading 75 | statusBar.tooltip = "loading..."; 76 | statusBar.show(); 77 | 78 | const config = vscode.workspace.getConfiguration("ruby-rstfilter"); 79 | const rstfilterPath: string = config.get("rstfilterLspPath") || "rstfilter-lsp"; 80 | 81 | let serverOption: ServerOptions = { 82 | "command": rstfilterPath, 83 | "args": [] 84 | }; 85 | 86 | let clientOption: LanguageClientOptions = { 87 | documentSelector: [ 88 | {scheme: "file", language: "ruby"} 89 | ] 90 | }; 91 | 92 | client = new LanguageClient( 93 | "vscode-rstfilter", 94 | "rstfilter extension", 95 | serverOption, 96 | clientOption 97 | ); 98 | 99 | client.onNotification("rstfilter/version", (params) => { 100 | rstfilterVersion = params.version; 101 | enableStatus(); 102 | }); 103 | 104 | client.onNotification("rstfilter/started", (params) => { 105 | const uri: string = params.uri; 106 | runningStauts(uri); 107 | }); 108 | 109 | client.onNotification("rstfilter/done", (_params) => { 110 | enableStatus(); 111 | }); 112 | 113 | client.onNotification("rstfilter/output", (params) => { 114 | if (!rstfilterOutput) { 115 | rstfilterOutput = vscode.window.createOutputChannel("rstfilter output"); 116 | } 117 | rstfilterOutput.clear(); 118 | rstfilterOutput.appendLine(params.output); 119 | rstfilterOutput.show(true); 120 | }); 121 | 122 | client.start(); 123 | 124 | return client; 125 | } 126 | 127 | function stopClient() { 128 | if (!client) { 129 | return undefined; 130 | } 131 | client.stop(); 132 | client = undefined; 133 | deleteStatus(); 134 | } 135 | 136 | --------------------------------------------------------------------------------