├── .gitignore ├── images └── books.png ├── .vscodeignore ├── .vscode ├── extensions.json ├── tasks.json ├── settings.json └── launch.json ├── CHANGELOG.md ├── tslint.json ├── tsconfig.json ├── LICENSE ├── src ├── fetchers.ts ├── extension.ts └── tldrRepository.ts ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .vscode-test/ 4 | *.vsix 5 | -------------------------------------------------------------------------------- /images/books.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bmuskalla/vscode-tldr/HEAD/images/books.png -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | src/** 5 | .gitignore 6 | vsc-extension-quickstart.md 7 | **/tsconfig.json 8 | **/tslint.json 9 | **/*.map 10 | **/*.ts -------------------------------------------------------------------------------- /.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 | "ms-vscode.vscode-typescript-tslint-plugin" 6 | ] 7 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "vscode-tldr" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## 1.0.0 8 | 9 | - Initial release 10 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-string-throw": true, 4 | "no-unused-expression": true, 5 | "no-duplicate-variable": true, 6 | "curly": true, 7 | "class-name": true, 8 | "semicolon": [ 9 | true, 10 | "always" 11 | ], 12 | "triple-equals": true 13 | }, 14 | "defaultSeverity": "warning" 15 | } 16 | -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 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 | "exclude": [ 18 | "node_modules", 19 | ".vscode-test" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /.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 | "name": "Run Extension", 9 | "type": "extensionHost", 10 | "request": "launch", 11 | "runtimeExecutable": "${execPath}", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/out/**/*.js" 17 | ], 18 | "preLaunchTask": "npm: watch" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Benjamin Muskalla 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 | -------------------------------------------------------------------------------- /src/fetchers.ts: -------------------------------------------------------------------------------- 1 | import { TldrFetcher, TldrPage } from "./TldrRepository"; 2 | import { Memento } from "vscode"; 3 | import { pathToFileURL } from "url"; 4 | const fetch = require("isomorphic-fetch"); 5 | 6 | export class CachingFetcher implements TldrFetcher { 7 | static readonly cacheKeyPrefix = "tldrfetcher.cache."; 8 | delegate: TldrFetcher; 9 | memento: Memento; 10 | 11 | constructor(memento: Memento, delegate: TldrFetcher) { 12 | this.delegate = delegate; 13 | this.memento = memento; 14 | } 15 | 16 | fetch(command: TldrPage): Thenable { 17 | const cacheKey = CachingFetcher.cacheKeyPrefix + command.command; 18 | let cachedPage = this.memento.get(cacheKey); 19 | if (cachedPage === undefined) { 20 | return this.delegate.fetch(command).then(page => { 21 | this.memento.update(cacheKey, page); 22 | return page; 23 | }); 24 | } 25 | return Promise.resolve(String(cachedPage)); 26 | } 27 | } 28 | 29 | export class GithubFetcher implements TldrFetcher { 30 | readonly baseUrl = 31 | "https://raw.githubusercontent.com/tldr-pages/tldr/master/pages/"; 32 | fetch(page: TldrPage): Thenable { 33 | let url = this.baseUrl + page.platform + "/" + page.command + ".md"; 34 | let content = fetch(url) 35 | .then((response: any) => response.text()) 36 | .then((text: any) => text); 37 | return content; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-tldr", 3 | "displayName": "tl;dr pages", 4 | "description": "Hover for commands using simplified and community-driven man pages.", 5 | "version": "1.0.0", 6 | "publisher": "bmuskalla", 7 | "author": { 8 | "name": "Benjamin Muskalla", 9 | "email": "b.muskalla@gmail.com" 10 | }, 11 | "license": "SEE LICENSE IN LICENSE", 12 | "engines": { 13 | "vscode": "^1.33.0" 14 | }, 15 | "icon": "images/books.png", 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/bmuskalla/vscode-tldr.git" 19 | }, 20 | "bugs": "https://github.com/bmuskalla/vscode-tldr/issues", 21 | "homepage": "https://github.com/bmuskalla/vscode-tldr/blob/master/README.md", 22 | "galleryBanner": { 23 | "color": "#313131", 24 | "theme": "dark" 25 | }, 26 | "categories": [ 27 | "Snippets", 28 | "Other" 29 | ], 30 | "keywords": [ 31 | "tldr", 32 | "man", 33 | "shell", 34 | "cli", 35 | "bash" 36 | ], 37 | "activationEvents": [ 38 | "onLanguage:dockerfile", 39 | "onLanguage:makefile", 40 | "onLanguage:powershell", 41 | "onLanguage:shellscript", 42 | "onLanguage:bat" 43 | ], 44 | "main": "./out/extension.js", 45 | "scripts": { 46 | "vscode:prepublish": "npm run compile", 47 | "compile": "tsc -p ./", 48 | "watch": "tsc -watch -p ./", 49 | "postinstall": "node ./node_modules/vscode/bin/install" 50 | }, 51 | "dependencies": { 52 | "isomorphic-fetch": "^2.2.1" 53 | }, 54 | "devDependencies": { 55 | "typescript": "^3.3.1", 56 | "vscode": "^1.1.28", 57 | "tslint": "^5.12.1", 58 | "@types/node": "^10.12.21" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vscode-tldr 2 | 3 | [![license](https://img.shields.io/github/license/bmuskalla/vscode-tldr.svg)](https://github.com/bmuskalla/vscode-tldr/blob/master/LICENSE) 4 | [![Visual Studio Marketplace](https://vsmarketplacebadge.apphb.com/version-short/bmuskalla.vscode-tldr.svg)](https://marketplace.visualstudio.com/items?itemName=bmuskalla.vscode-tldr) 5 | 6 | Provides [tldr](https://github.com/tldr-pages/tldr/) hover information for common commands in bash/dockerfiles/powershell files. tldr-pages is a collection of simplified and community-driven man pages. 7 | 8 | ## Demo 9 | 10 | ### Shell scripts 11 | 12 | ![tldr hover in shell scripts](https://user-images.githubusercontent.com/316929/56687643-10f4ef00-66d7-11e9-9c71-d70a8a8d5e87.gif) 13 | 14 | ### Batch files 15 | 16 | ![tldr hover in batch files](https://user-images.githubusercontent.com/316929/56687640-10f4ef00-66d7-11e9-992a-3301c89fcafc.gif) 17 | 18 | ### Dockerfile 19 | 20 | ![tldr hover in docker file](https://user-images.githubusercontent.com/316929/56687642-10f4ef00-66d7-11e9-8c43-d3cfe8d9169d.gif) 21 | 22 | ## How to use it? 23 | 24 | Hover over a command using your mouse or use the 'Show Hover' command in VS Code (by default, ⌘ Command + K ⌘ Command + I). 25 | tldr hovers are available in the following language modes: 26 | 27 | - Dockerfile 28 | - Shell script 29 | - Powershell 30 | - Makefile 31 | - Batch 32 | 33 | ## What does "tldr" mean? 34 | 35 | TL;DR stands for "Too Long; Didn't Read". 36 | It originates in Internet slang, where it is used to indicate that a long text 37 | (or parts of it) has been skipped as too lengthy. 38 | Read more in Wikipedia's [TL;DR article](https://en.wikipedia.org/wiki/TL;DR). 39 | 40 | **Enjoy!** 41 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { TldrRepository, TldrFetcher } from "./TldrRepository"; 3 | import { CachingFetcher, GithubFetcher } from "./fetchers"; 4 | 5 | export function activate(context: vscode.ExtensionContext) { 6 | let fetcher = new CachingFetcher(context.globalState, new GithubFetcher()); 7 | let repository = new TldrRepository(fetcher); 8 | 9 | let provider: vscode.HoverProvider = newTldrHoverProvider(repository); 10 | let supportedLanguageModes = [ 11 | "dockerfile", 12 | "makefile", 13 | "powershell", 14 | "shellscript", 15 | "bat" 16 | ]; 17 | 18 | registerHoverWithSupportedLanguages( 19 | context, 20 | supportedLanguageModes, 21 | provider 22 | ); 23 | } 24 | 25 | function newTldrHoverProvider( 26 | repository: TldrRepository 27 | ): vscode.HoverProvider { 28 | return { 29 | provideHover(document, position, token) { 30 | let currentTokenRange = document.getWordRangeAtPosition(position); 31 | if (currentTokenRange !== undefined && currentTokenRange.isSingleLine) { 32 | let currentToken = document.getText(currentTokenRange); 33 | const pageMarkdown = repository.getMarkdown(currentToken); 34 | return pageMarkdown.then( 35 | markdown => new vscode.Hover(markdown), 36 | rejected => null 37 | ); 38 | } 39 | } 40 | }; 41 | } 42 | 43 | function registerHoverWithSupportedLanguages( 44 | context: vscode.ExtensionContext, 45 | supportedEditors: string[], 46 | provider: vscode.HoverProvider 47 | ) { 48 | supportedEditors.forEach(lang => { 49 | const selectors = [ 50 | { scheme: "untitled", language: lang }, 51 | { scheme: "file", language: lang } 52 | ]; 53 | let disposable = vscode.languages.registerHoverProvider( 54 | selectors, 55 | provider 56 | ); 57 | context.subscriptions.push(disposable); 58 | }); 59 | } 60 | 61 | export function deactivate() {} 62 | -------------------------------------------------------------------------------- /src/tldrRepository.ts: -------------------------------------------------------------------------------- 1 | import { MarkdownString, commands } from "vscode"; 2 | import { platform } from "os"; 3 | 4 | export interface TldrFetcher { 5 | fetch(command: TldrPage): Thenable; 6 | } 7 | 8 | export class TldrPage { 9 | platform: TldrPlatform; 10 | command: string; 11 | 12 | constructor(platform: TldrPlatform, command: string) { 13 | this.platform = platform; 14 | this.command = command; 15 | } 16 | 17 | toString(): string { 18 | return this.platform + "/" + this.command; 19 | } 20 | } 21 | 22 | export enum TldrPlatform { 23 | Common = "common", 24 | Linux = "linux", 25 | OSX = "osx", 26 | SunOS = "sunos", 27 | Windows = "windows" 28 | } 29 | 30 | const fetch = require("isomorphic-fetch"); 31 | 32 | class TldrIndex { 33 | pages: TldrPage[] = []; 34 | 35 | readonly baseUrl = 36 | "https://api.github.com/repos/tldr-pages/tldr/contents/pages/"; 37 | 38 | constructor() { 39 | this.initializeData(); 40 | } 41 | 42 | async initializeData() { 43 | Object.values(TldrPlatform).forEach(async platform => { 44 | await this.fetchPageIndex(platform); 45 | }); 46 | } 47 | 48 | fetchPageIndex(platformToFetch: TldrPlatform): Promise { 49 | return fetch(this.baseUrl + platformToFetch) 50 | .then((response: any) => response.json()) 51 | .then((data: any) => { 52 | let doc; 53 | for (doc of data) { 54 | let commandName = doc.name.split(".")[0]; 55 | let page = new TldrPage(platformToFetch, commandName); 56 | this.pages.push(page); 57 | } 58 | }); 59 | } 60 | 61 | isAvailable(command: string) { 62 | return this.pages.filter((p: TldrPage) => p.command === command)[0]; 63 | } 64 | } 65 | 66 | export class TldrRepository { 67 | fetcher: TldrFetcher; 68 | index: TldrIndex; 69 | 70 | constructor(fetcher: TldrFetcher) { 71 | this.fetcher = fetcher; 72 | this.index = new TldrIndex(); 73 | } 74 | 75 | getMarkdown(command: string): Thenable { 76 | let page = this.index.isAvailable(command); 77 | if (page) { 78 | return this.fetcher 79 | .fetch(page) 80 | .then(text => new MarkdownString(this.format(text))); 81 | } 82 | return Promise.reject(new MarkdownString("not available")); 83 | } 84 | 85 | format(contents: string): string { 86 | contents = contents.replace("\n> ", "\n"); 87 | let headline = contents.indexOf("\n"); 88 | return contents.substring(headline); 89 | } 90 | } 91 | --------------------------------------------------------------------------------