Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
md
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,28 @@ go build -o md .

```
Usage:
md [flags] <markdown-file>
md [flags] [markdown-file]

Flags:
-h, --help help for md
-v, --vim Enable vim-style navigation
-h, --help help for md
-p, --plain Render entire markdown to stdout (no pager)
```

By default, `md` displays content in a vim-style pager. Use `--plain` to output directly to stdout.

### Reading from stdin

You can pipe markdown content directly to `md`:

```bash
cat README.md | md
echo "# Hello World" | md
curl -s https://example.com/doc.md | md
```

### Vim Navigation Keys

When using `--vim` mode, you can navigate using:
In the default pager mode, you can navigate using:

- `j` / `k` - Move down/up
- `gg` - Go to top
Expand Down
66 changes: 39 additions & 27 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"fmt"
"io"
"os"
"path/filepath"

Expand All @@ -15,49 +16,60 @@ import (

var (
plainMode bool
watchMode bool
)

var rootCmd = &cobra.Command{
Use: "md [flags] <markdown-file>",
Use: "md [flags] [markdown-file]",
Short: "A markdown renderer and viewer for the terminal",
Long: `md is a command-line tool that renders markdown files with syntax highlighting
and provides options for vim-style navigation.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
filename := args[0]
if !filepath.IsAbs(filename) {
var err error
filename, err = filepath.Abs(filename)
if err != nil {
return fmt.Errorf("error resolving file path: %v", err)
}
}

if _, err := os.Stat(filename); os.IsNotExist(err) {
return fmt.Errorf("file not found: %s", filename)
}
and provides options for vim-style navigation.

If no file is provided, md reads from stdin.`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
themeManager := theme.New()
mdRenderer := renderer.New(themeManager)
codeHighlighter := highlighter.New(themeManager)
mdViewer := viewer.New()

renderAndDisplay := func() error {
content, err := mdRenderer.RenderFile(filename, codeHighlighter)
if err != nil {
return fmt.Errorf("rendering error: %v", err)
var content string
var err error

if len(args) == 0 || args[0] == "-" {
// Read from stdin
stdinContent, readErr := io.ReadAll(os.Stdin)
if readErr != nil {
return fmt.Errorf("error reading from stdin: %v", readErr)
}
if len(stdinContent) == 0 {
return fmt.Errorf("no input provided")
}
content, err = mdRenderer.RenderContent(stdinContent, codeHighlighter)
} else {
filename := args[0]
if !filepath.IsAbs(filename) {
filename, err = filepath.Abs(filename)
if err != nil {
return fmt.Errorf("error resolving file path: %v", err)
}
}

if plainMode {
fmt.Print(content)
return nil
} else {
return mdViewer.DisplayInVimMode(content)
if _, statErr := os.Stat(filename); os.IsNotExist(statErr) {
return fmt.Errorf("file not found: %s", filename)
}

content, err = mdRenderer.RenderFile(filename, codeHighlighter)
}

return renderAndDisplay()
if err != nil {
return fmt.Errorf("rendering error: %v", err)
}

if plainMode {
fmt.Print(content)
return nil
}
return mdViewer.DisplayInVimMode(content)
},
}

Expand Down