Giter Site home page Giter Site logo

gh-markdown-preview's Introduction

gh markdown-preview

GitHub CLI extension to preview Markdown looks like GitHub :octocat:

gh markdown-preview is a GitHub CLI extension to preview your markdown such as README.md. The gh markdown-preview command start a local web server to serve the markdown document. gh markdown-preview renders the HTML got from GitHub official markdown API and uses the CSS extracted from GitHub web site. The styles are almost the same!

You can see rendered README before uploading to GitHub!

Features

  • No-dependencies - You need gh command only.
  • Zero-configuration - You don't have to set the GitHub access token.
  • Looks exactly the same - You can see same as GitHub.
  • Live reloading - You don't need reload the browser.
  • Auto open browser - Your browser will be opened automatically.
  • Auto find port - You don't need find an available port if default is used.

Screenshots

Open your browser:

Screenshot of gh markdown-preview

Live reloading:

Screenshot of gh markdown-preview

Installation

gh extension install yusukebe/gh-markdown-preview

Upgrade:

gh extension upgrade markdown-preview

Usage

The usage:

gh markdown-preview README.md

Or this command will detect README file in the directory automatically.

gh markdown-preview

Then access the local web server such as http://localhost:3333 with Chrome, Firefox, or Safari.

Available options:

    --dark-mode           Force dark mode
    --disable-auto-open   Disable auto opening your browser
    --disable-reload      Disable live reloading
-h, --help                help for gh-markdown-preview
    --host string         Hostname this server will bind (default "localhost")
    --light-mode          Force light mode
-p, --port int            TCP port number of this server (default 3333)
    --verbose             Show verbose output
    --version             Show the version

Related projects

Author

Yusuke Wada http://github.com/yusukebe

License

Distributed under the MIT License.

gh-markdown-preview's People

Contributors

joshbainbridge avatar parroty avatar shortarrow avatar tedroden avatar yusukebe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

gh-markdown-preview's Issues

Live Reloading Not Working

Both gh markdown-preview --reload gh markdown-preview -r are not working.

I'm using Ubuntu with WSL, it wasn't working on Firefox on Windows. I opened the Linux version but that didn't work either. I also tried Edge and nothing.

I'm editing my README.md inside Vim. I don't expect live changes but I expected changes everytime I save changes.

Alerts not Rendered as expected in Native Github Webpage

Alerts aren't rendered in localhost of the markdown file.

So a quick backstory, I was doing my chemistry work and wanted to use Alerts as a means of writing questions and rendered the file using the extension, i.e., gh markdown-preview ./Chemistry/hydrocarbons.md. Haven't used any tags (as seen in the screenshot below) because its the first file I opened using this extension. Would continue to use it daily if this problem is fixed.

Tip

Right click and open the image to view the actual quality picture.

File as rendered by Github Webpage and the code written

Code rendered in localhost with the Extension

For assurance, check the tabs to verify the files opened by Firefox.


Btw, don't mind the unprofessional writing in this issue, I'm new to writing issues.
Nonetheless, the output is in the terminal screenshot.
If you missed that, go to the link of the file to open a higher quality picture.

Throw Error if README.md does not exists

Currently, the "gh-markdown-preview" starts and prints Open http://* on your browser, although markdown file is not specified in the current directory and REAMDE.md does not exist. CLI should throw "Not Found" error.

README page width not the same as on GitHub

Firstly, this is great extension, thanks for all the hard work ๐Ÿ™

I recently noticed the Markdown body of any README page is rendering at 890px when using markdown-preview, as opposed to 830px when viewing the same page directly on GitHub.

I'm not sure if getting a one-to-one match is important to the project, but thought it worth mentioning in case it wasn't known. I'd presume the fix might be as simple as:

--- a/cmd/template.html
+++ b/cmd/template.html
@@ -27,7 +27,7 @@
       .markdown-body {
         box-sizing: border-box;
         min-width: 200px;
-        max-width: 980px;
+        max-width: 920px;
         margin: 0 auto;
         padding: 45px;
       }

Tested on Safari Version 16.5 with macOS 13.4.

Anchor Tag Not Working

When gh-markdown-preview creates anchor tags it adds "user-content-" to the id.

For example, if the user creates a markdown header called "My Anchor", gh-markdown-preview set the id to "user-content-my-anchor" instead of "my-anchor".

"Add support for secure token storage"

Token storage change in latest release of gh

This is a message from the GitHub CLI team, maintainers of gh, writing to inform you that the most recent release of gh contains changes which may affect your extension. The latest release introduces the feature of storing authentication tokens in the system keyring (encrypted storage) instead of in a plain text file.
The keyrings that are supported are:

  • Keychain on macOS

  • GNOME Keyring on Linux (Secret Service dbus interface)

  • Wincred on Windows

This has huge security benefits for the users of our tool and was one of our oldest outstanding issues. Unfortunately this change has the potential to break extensions that rely on utilizing the users authentication token to work.

In order to have continued compatibility with gh there are some actions you, as an extension author, need to take. These actions will depend on the implementation of your extension.

Extensions built in Go using go-gh:

  1. Upgrade your go-gh version to v1.2.1, the latest version.

  2. Verify that in your extension retrieval of the user authentication token is done using the auth.TokenForHost function.

    • If you were previously accessing the authentication token using any other method it will no longer work.
    • Automatic resolution of the authentication token when using the API clients will continue to work without changes.

All other extensions:

  1. Verify that in your extension retrieval of the user authentication token is done by shelling out to the gh auth token command.

    • If you were previously accessing the authentication token using the gh config get command, reading the configuration file directly, or any other methods it will no longer work.

As of right now storing the authentication token in the system keyring is an opt-in feature, but in the near future it will be required and at that point if the changes above are not made then your extension will be broken for all users. If you have any questions/concerns about this change please feel free to open a discussion in the gh repo.

Thanks,
The GitHub CLI Team

add this script to generate automatically clipboard button

official github script

function createNode(text: string): Element {
  const node = document.createElement('pre')
  node.style.width = '1px'
  node.style.height = '1px'
  node.style.position = 'fixed'
  node.style.top = '5px'
  node.textContent = text
  return node
}

function copyNode(node: Element): Promise<void> {
  if ('clipboard' in navigator) {
    return navigator.clipboard.writeText(node.textContent || '')
  }

  const selection = getSelection()
  if (selection == null) {
    return Promise.reject(new Error())
  }

  selection.removeAllRanges()

  const range = document.createRange()
  range.selectNodeContents(node)
  selection.addRange(range)

  document.execCommand('copy')
  selection.removeAllRanges()
  return Promise.resolve()
}

export function copyText(text: string): Promise<void> {
  if ('clipboard' in navigator) {
    return navigator.clipboard.writeText(text)
  }

  const body = document.body
  if (!body) {
    return Promise.reject(new Error())
  }

  const node = createNode(text)
  body.appendChild(node)
  copyNode(node)
  body.removeChild(node)
  return Promise.resolve()
}

an other script found online

// copy code icon markup
const copyIcon = `<svg aria-hidden="true" data-testid="geist-icon" fill="none" height="18" shape-rendering="geometricPrecision" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" width="18" style="color: currentcolor;"><path d="M8 17.929H6c-1.105 0-2-.912-2-2.036V5.036C4 3.91 4.895 3 6 3h8c1.105 0 2 .911 2 2.036v1.866m-6 .17h8c1.105 0 2 .91 2 2.035v10.857C20 21.09 19.105 22 18 22h-8c-1.105 0-2-.911-2-2.036V9.107c0-1.124.895-2.036 2-2.036z"></path></svg>`

// insert copy buttons for code blocks
const codeBlocks = document.querySelectorAll("div.h-r")
codeBlocks.forEach((codeBlock) => {
    codeBlock.insertAdjacentHTML(
        "afterbegin",
        `<button class="copy" aria-label="Copy code to clipboard" style="float:right;">${copyIcon}</button>`
    )


})

// handler that saves the code block innerText to clipboard
function copyCodeBlock(event) {
    const copyButton = event.currentTarget
    // const codeBlock = copyButton.parentElement.querySelector("pre.highlight")  
    // const code = codeBlock.innerText.trim()


    const codeBlock = this.parentNode.querySelector("pre.h").lastChild
    const code = codeBlock.data.trim()

    // remove "$ " prompt at start of lines in code
    const strippedCode = code.replace(/^[\s]?\$\s+/gm, "")
    window.navigator.clipboard.writeText(strippedCode)

    // change the button text temporarily
    copyButton.textContent = "Copied!"
    setTimeout(() => copyButton.innerHTML = copyIcon, 3000)
}

// register event listeners for copy buttons
const copyButtons = document.querySelectorAll("button.copy")
copyButtons.forEach((btn) => {
    btn.addEventListener("click", copyCodeBlock)
})

Inconvenient URL output on startup

I'm on current Arch Linux with the current version of gh and this extension. On start, it outputs:

$ gh markdown-preview README.md
2022/04/07 15:27:37 Accepting connections at http://*:3333/
2022/04/07 15:27:37 Open http://*:3333/ on your browser
2022/04/07 15:27:37 GET [200] /
2022/04/07 15:27:37 Watching README.md for changes
2022/04/07 15:27:37 GET [404] /favicon.ico
2022/04/07 15:27:38 GET [200] /__/md

All other similar utilities (i.e grip for a specific example) that create a local web-server output a valid click-able URL in the terminal which you can just click on to conveniently jump to in your browser. I know the browser is automatically opened the first time but you may want to open it a second/later time. So please change that http://*:3333/ to http://localhost:3333/.

I suspect you may want to argue that http://*:3333/ informs the user that the port is opened globally but, as possibly another issue, I suggest from a security/privacy standpoint that the port should only be opened locally (i.e. on localhost) by default anyhow. Add another option -g/--global and thus for the rare case when a user needs this he obviously already knows what URL to use.

I've previously used grip but it has some annoying failures (currently broken with a Python error on Arch Linux) so I am looking for an alternative.

Prepare default `/favicon.ico` ?

In most cases, there is no favicon.ico in our directory and it will be 404 not found. How about preparing the default favicon.ico and showing it as /favicon.ico.

SS

it can not used on Windows

>gh  markdown-preview test.md
--: C:\Users\lenovo\AppData\Local\GitHub CLI\extensions\gh-markdown-preview\gh-markdown-preview: /usr/bin/env: bad interpreter: Permission denied

Add --export option like grip

Sometimes you just want to render a markdown file directly to a HTML file. grip provides an option to do this:

grip --export README.html

For this case, no server is started, no browser tab is opened, etc. Also can specify '-' for stdout.

Can this option please be added here?

Usage with emacs for multiple files

This is not an issue.

It's more of a thank you and a rudimentary emacs usage as I found this extension much more helpfull than using pandoc with emacs markdown mode on *nix like systems. I use this on Ubuntu 20.04.3 LTS and GNU Emacs 26.3.

Feel free to comment or just close this issue as you see fit.

To use this gh extension with emacs:

  1. insert into the .emacs file (or equivalent):
(defun md_preview ()
  "start /usr/bin/gh markdown-preview -p PORT <current buffer file>"
  (interactive)
  (let (PORT BFN BFN_PORT)
    (setq PORT (read-string "PORT: " nil nil "3333"))  
    (setq BFN (buffer-file-name))
    (setq BFN_PORT (concat BFN ":" PORT))
    (start-process "gh_markdown_preview" BFN_PORT "/usr/bin/gh" "markdown-preview" "-p" PORT BFN)))

(global-set-key [(control ?x) (p)] 'md_preview)
  1. restart emacs and open a couple of markdown files.
  2. to preview a buffer with a markdown file by using a web browser and the url http://localhost:3333: in emacs "C-x p" RET (to use the default port 3333)
  3. to preview a second buffer with a different markdown file in a web browser and the url http://localhost:3334: in emacs "C-x p" 3334 RET (or any port that isn't in use such as 3333 in this example)
  4. the lisp code above will put output from the gh markdown-preview instances into separate buffers named like /path/to/markdown-file.md:3333, /path/to/different-markdown-file.md:3334, etc. in emacs
  5. close the /path/to/markdown-file.md:3333 emacs buffer to exit the preview processes on port 3333 (and free the port)

This emacs implementation has shortcomings:
A. The user must keep track of what port is open and available for use
B. I'm not sure if this is the best solution if one is editing several hundred md files. I only edit a handful so I suspect it will work just fine for that.
C. While I've used emacs for some time, the above is a first attempt at coding lisp. It works for me but there are likely many more shortcomings than A & B above. Treat this a place to start, not an end point.

HTH

and thanks again - it's really handy.

EDITs - the original code posted didn't work. The code above does, is a bit simpler, and perhaps makes it easier to keep track of what markdown file is being displayed on what port.

WebSocket Error

With --reload option, error has been happened.

2021/12/02 04:19:52 Change detected in README.md, refreshing
2021/12/02 04:19:52 Change detected in README.md, refreshing
2021/12/02 04:19:52 error:websocket: close sent

Needless `<a>` tag in markdown preview

There is needless <a> tag in markdown preview
SCR-20231220-jmqp

when I copy it to my note or word, there will be an useless extra hyperlink
Hoping to delete it. I don't need an localhost hyperlink in my word document.
image

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.