├── .gitignore ├── .npmignore ├── screencapture.gif ├── shell-matcher.js ├── package.json ├── README.md ├── markdown.js └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | screencapture.gif -------------------------------------------------------------------------------- /screencapture.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elmasse/hyper-markdown-preview/HEAD/screencapture.gif -------------------------------------------------------------------------------- /shell-matcher.js: -------------------------------------------------------------------------------- 1 | 2 | exports.sh = /(?:ba)?sh: ((?:file:\/\/)|(?:\/\/))?(.*): (?:(?:command not found)|(?:No such file or directory))/; 3 | exports.bash = exports.sh; 4 | exports.zsh = /zsh: (?:(?:command not found)|(?:no such file or directory)): ((?:file:\/\/)|(?:\/\/))?([^\r\n]+)/; 5 | exports.fish = /fish: Unknown command '((?:file:\/\/)|(?:\/\/))?([^']+)'/; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyper-markdown-preview", 3 | "version": "1.1.3", 4 | "description": "Hyper plugin to preview markdown files right in your terminal.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "hyper", 11 | "hyperterm", 12 | "markdown", 13 | "md", 14 | "preview" 15 | ], 16 | "author": { 17 | "name": "Maximiliano Fierro", 18 | "email": "elmasse@gmail.com" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/elmasse/hyper-markdown-preview.git" 23 | }, 24 | "bugs": { 25 | "url": "https://github.com/elmasse/hyper-markdown-preview/issues" 26 | }, 27 | "license": "ISC", 28 | "dependencies": { 29 | "highlight.js": "^9.9.0", 30 | "remarkable": "^1.7.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hyper-markdown-preview 2 | 3 | [](https://www.npmjs.com/package/hyper-markdown-preview) 4 | [](https://www.npmjs.com/package/hyper-markdown-preview) 5 | 6 | 7 | A plugin to preview markdown files in your Hyper term. 8 | 9 | 10 | ## Usage 11 | 12 | Just type the location of your markdown file in your terminal. 13 | 14 |  15 | 16 | ## Install 17 | 18 | Add the hyper-markdown-preview to your `.hyper.js` config file. 19 | 20 | ```js 21 | module.exports = { 22 | //... 23 | plugins: [ 24 | `hyper-markdown-preview` 25 | ], 26 | //... 27 | } 28 | ``` 29 | 30 | ## Config 31 | 32 | Since version 1.1 you can configure the stylesheets to use when rendering the markdown. 33 | 34 | ```js 35 | module.exports = { 36 | config: { 37 | // ... 38 | 39 | hyperMarkdownPreview: { 40 | stylesheet: 'github' // github | none 41 | } 42 | } 43 | 44 | // ... 45 | } 46 | 47 | ``` -------------------------------------------------------------------------------- /markdown.js: -------------------------------------------------------------------------------- 1 | 2 | const Remarkable = require('remarkable'); 3 | const hljs = require('highlight.js'); 4 | 5 | const md = new Remarkable({ 6 | html: true, 7 | linkify: true, 8 | typographer: true, 9 | highlight: function (str, lang) { 10 | if (lang && hljs.getLanguage(lang)) { 11 | try { 12 | return hljs.highlight(lang, str).value; 13 | } catch (err) {} 14 | } 15 | 16 | try { 17 | return hljs.highlightAuto(str).value; 18 | } catch (err) {} 19 | 20 | return ''; // use external default escaping 21 | } 22 | }); 23 | 24 | 25 | const imageRender = (options, imgFn) => (tokens, idx, opts /*, env */) => { 26 | const src = tokens[idx].src; 27 | const isLocal = !src.match(/^http|file/); 28 | if (isLocal) { 29 | tokens[idx].src = createLocalUri(options.cwd, src); 30 | } 31 | return imgFn(tokens, idx, opts /*, env */); 32 | } 33 | 34 | const createLocalUri = (cwd, src) => { 35 | let uri = src; 36 | 37 | if (src.match(/^\./)) { 38 | uri = src.substring(1); 39 | } 40 | 41 | if (!src.match(/^\//)) { 42 | uri = `/${uri}`; 43 | } 44 | 45 | return `file://${cwd}${uri}`; 46 | } 47 | 48 | exports.markdown = md; 49 | 50 | exports.replaceLocalImagePlugin = (instance, options) => { 51 | const imgFn = instance.renderer.rules.image; 52 | instance.renderer.rules.image = imageRender(options, imgFn) 53 | } 54 | 55 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { existsSync, readFileSync } = require('fs'); 2 | const { exec } = require('child_process'); 3 | const { resolve } = require('path'); 4 | 5 | const { markdown, replaceLocalImagePlugin } = require('./markdown'); 6 | const matcher = require('./shell-matcher'); 7 | 8 | const resolveCWD = (pid, cb) => { 9 | exec(`lsof -n -p ${pid} | grep cwd | tr -s ' ' | cut -d ' ' -f9-`, (err, cwd) => { 10 | if (err) { 11 | cb(err, null); 12 | } else { 13 | cwd = cwd.trim(); 14 | cb(null, cwd); 15 | } 16 | }); 17 | } 18 | 19 | const hyperMarkdownPreview = { 20 | stylesheet: 'github' 21 | } 22 | 23 | exports.decorateConfig = (config) => { 24 | console.log(config) 25 | return Object.assign({ 26 | hyperMarkdownPreview 27 | }, config); 28 | } 29 | 30 | const stylesheets = { 31 | github: ``, 32 | none: `` 33 | } 34 | 35 | exports.middleware = (store) => (next) => (action) => { 36 | 37 | if ('SESSION_ADD_DATA' === action.type) { 38 | const { data } = action; 39 | const state = store.getState(); 40 | const { sessions } = state; 41 | const { activeUid } = sessions; 42 | const session = sessions.sessions[activeUid]; 43 | const { pid, shell } = session; 44 | const match = data.match(matcher[shell]); 45 | const globalCfg = window.config.getConfig(); 46 | const config = globalCfg.hyperMarkdownPreview || hyperMarkdownPreview; 47 | if (match) { 48 | const file = match[2]; 49 | if (/\.(md|markdown)$/.test(file)) { 50 | 51 | resolveCWD(pid, (err, cwd) => { 52 | if (err) { 53 | console.log('Cannot retrieve CWD', err); 54 | return; 55 | } 56 | 57 | const path = resolve(cwd, file); 58 | 59 | if (existsSync(path)) { 60 | 61 | markdown.use(replaceLocalImagePlugin, {cwd}); 62 | 63 | const source = readFileSync(path, 'UTF-8'); 64 | const style = stylesheets[config.stylesheet] || stylesheets.github; 65 | const html = ` 66 |
67 | 68 | ${style} 69 | 77 | 78 | ${markdown.render(source)} 79 | `; 80 | 81 | const url = URL.createObjectURL(new Blob([html],{type: 'text/html'})) 82 | // const url = `data:text/html,${html}`; 83 | 84 | store.dispatch({ 85 | type: 'SESSION_URL_SET', 86 | uid: activeUid, 87 | url 88 | }); 89 | 90 | } else { 91 | next(action); 92 | } 93 | }); 94 | } else { 95 | next(action); 96 | } 97 | } else { 98 | next(action); 99 | } 100 | } else { 101 | next(action); 102 | } 103 | }; 104 | --------------------------------------------------------------------------------