Code Monkey home page Code Monkey logo

tldr-emacs-extension's Introduction

tldr-emacs-extension

Requirenments

  • tldr-lint installed
  • emacs 27.1 higher
  • yasnippet (optional, if snippets must be enabled)

Features

  • Code linting
  • Code snippets
  • Code actions

linting

settings

Installation

Copy-paste plugin script contents to ~/.emacs while enabling lexical-binding

Example ~/.emacs config:

;;; flymake-tldr-lint.el --- A TlDr Flymake backend powered by tldr-lint  -*- lexical-binding: t; -*-
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)

;; The extension file content with all comments removed can be placed here.

(add-hook 'markdown-mode-hook 'flymake-tldr-lint-load)

(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(package-selected-packages '(markdown-mode)))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
)

Starting linting

  • Use M-x flymake-mode RET (view the next chapter below to understand how to interpret M-x and RET)

Starting fixing

⚠️ tldr- prefix was replaced with flymake-tldr-lint- in actions.

To speed up fixing TlDr pages several examples provided for each code fix down below:

  • Action: flymake-tldr-lint-remove-broken-ellipsis Input: command {{...}} Result: command

  • Action: flymake-tldr-lint-remove-broken-numbers Input: command {{path/to/file_1}} Result: command {{path/to/file}}

  • Action: flymake-tldr-lint-remove-broken-files Input: command {{file}} Result: command

  • Action: flymake-tldr-lint-remove-broken-directories Input: command {{dir}} Result: command

  • Action: flymake-tldr-lint-correct-broken-ellipsis Input: command {{path/to/file1}} {{path/to/file2}} {{path/to/file3}} Result: command {{path/to/file1 path/to/file2 ...}}

  • Action: flymake-tldr-lint-correct-broken-numbers Input: command {{path/to/file_1}} Result: command {{path/to/file1}}

  • Action: flymake-tldr-lint-correct-broken-files Input: command {{file}} Result: command {{path/to/file}}

  • Action: flymake-tldr-lint-correct-broken-directories Input: command {{dir}} Result: command {{path/to/directory}}

  • Action: flymake-tldr-lint-correct-broken-ranges Input: command {{1-10}} Result: command {{1..10}}

  • Action: flymake-tldr-lint-correct-broken-long-option-argument Input: command --option {{option}} Result: command --option {{any}}

  • Action: flymake-tldr-lint-correct-broken-mnemonics Input:

    - Invoke command with option used:
    
    `command -opt {{option}}`

    Result:

    - Invoke command with [opt]ion used:
    
    `command -opt {{option}}`
  • Action: flymake-tldr-lint-convert-long-option-space-separated Input: command --option={{any}} Result: command --option {{any}}

  • Action: flymake-tldr-lint-convert-long-option-equal-sign-separated Input: command --option {{any}} Result: command --option={{any}}

  • Action: flymake-tldr-lint-remove-broken-all

  • Action: flymake-tldr-lint-correct-broken-all

⚠️ Note that all actions are regex-based substitutions. If you need more smart behaviour use TlDr extensions for another editor.

Actions in action

For instace we have the following tar page:

# tar

> Archiving utility.
> Often combined with a compression method, such as gzip or bzip2.
> More information: <https://www.gnu.org/software/tar>.

- [c]reate an archive and write it to a [f]ile:

`tar cf {{target.tar}} {{file1}} {{file2}} {{file3}}`

- [c]reate a g[z]ipped archive and write it to a [f]ile:

`tar czf {{target.tar.gz}} {{file1}} {{file2}} {{file3}}`

- [c]reate a g[z]ipped archive from a directory using relative paths:

`tar czf {{target.tar.gz}} --directory={{path/to/directory}} .`

- E[x]tract a (compressed) archive [f]ile into the current directory [v]erbosely:

`tar xvf {{source.tar[.gz|.bz2|.xz]}}`

- E[x]tract a (compressed) archive [f]ile into the target directory:

`tar xf {{source.tar[.gz|.bz2|.xz]}} --directory={{path/to/directory}}`

- [c]reate a compressed archive and write it to a [f]ile, using [a]rchive suffix to determine the compression program:

`tar caf {{target.tar.xz}} {{file1}} {{file2}} {{file3}}`

- Lis[t] the contents of a tar [f]ile [v]erbosely:

`tar tvf {{source.tar}}`

- E[x]tract files matching a pattern from an archive [f]ile:

`tar xf {{source.tar}} --wildcards "{{*.html}}"`

To fix all fixable issues at once we can use M-x flymake-tldr-lint-correct-broken-all command. The result is as follows:

# tar

> Archiving utility.
> Often combined with a compression method, such as gzip or bzip2.
> More information: <https://www.gnu.org/software/tar>.

- [c]reate an archive and write it to a [f]ile:

`tar cf {{target.tar}} {{path/to/file1 path/to/file2 ...}}`

- [c]reate a g[z]ipped archive and write it to a [f]ile:

`tar czf {{target.tar.gz}} {{path/to/file1 path/to/file2 ...}}`

- [c]reate a g[z]ipped archive from a directory using relative paths:

`tar czf {{target.tar.gz}} --directory={{path/to/directory}} .`

- E[x]tract a (compressed) archive [f]ile into the current directory [v]erbosely:

`tar xvf {{source.tar[.gz|.bz2|.xz]}}`

- E[x]tract a (compressed) archive [f]ile into the target directory:

`tar xf {{source.tar[.gz|.bz2|.xz]}} --directory={{path/to/directory}}`

- [c]reate a compressed archive and write it to a [f]ile, using [a]rchive suffix to determine the compression program:

`tar caf {{target.tar.xz}} {{path/to/file1 path/to/file2 ...}}`

- Lis[t] the contents of a tar [f]ile [v]erbosely:

`tar tvf {{source.tar}}`

- E[x]tract files matching a pattern from an archive [f]ile:

`tar xf {{source.tar}} --wildcards "{{*.html}}"`

{{target.tar}} placeholder and similar ones were not fixed as extension didn't recognized them as path placeholders.

Settings

To change settings M-x customize-option RET {{flymake-tldr-lint-program|flymake-tldr-lint-ignored}} RET can be used where:

  • M-x is Alt with x
  • RET is Enter.

Settings:

  • flymake-tldr-lint-program (default: "tldr-lint") - executable name
  • flymake-tldr-lint-ignored (default: "") - list of ignored errors (as a delimiter any character can be used TLDR004 TLDR006 or TLDR004,TLDR006)

FAQ

  • Can I remove broken placeholders automatically? This can be done via all flymake-tldr-lint-remove-broken-* actions.
  • Can I fix broken placeholders automatically? This can be done via all flymake-tldr-lint-correct-broken-* actions.

tldr-emacs-extension's People

Contributors

syohex avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

Forkers

syohex

tldr-emacs-extension's Issues

Add interactive functions to remove or fix potentially broken placeholders

(defun replace-regexp-entire-buffer (pattern replacement)
  "Perform regular-expression replacement throughout buffer."
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward pattern nil t)
      (replace-match replacement))))

(defun tldr-remove-broken-ellipsis()
  "Remove {{...}} placeholders in the current buffer."
  (interactive)
  (with-current-buffer (current-buffer)
    (replace-regexp-entire-buffer "[ ]*{{\\.\\{3\\}}}[ ]*" "")
    (message "Save file to update list of TlDr errors")
  )
)

(defun tldr-remove-broken-numbers()
  "Replace {{placeholder_number}} placeholders with {{placeholder}} in the current buffer."
  (interactive)
  (with-current-buffer (current-buffer)
    (replace-regexp-entire-buffer "{{\\([^{}_]+\\)_+\\(?:[0-9]+\\)}}" "{{\\1}}")
    (message "Save file to update list of TlDr errors")
  )
)

(defun tldr-remove-broken-files()
  "Remove {{file}}, {{filename}}, and {{file_name}} placeholders in the current buffer.
Trailing numbers are respected too."
  (interactive)
  (with-current-buffer (current-buffer)
    (replace-regexp-entire-buffer "[ ]*{{file_?\\(?:name\\)?\\(?:[0-9]+\\)}}[ ]*" "")
    (message "Save file to update list of TlDr errors")
  )
)

(defun tldr-remove-broken-directories()
  "Remove {{dir}}, {{dirname}}, {{dir_name}}, {{directory}}, {{directoryname}}, and {{directory_name}} placeholders in the current buffer.
Trailing numbers are respected too."
  (interactive)
  (with-current-buffer (current-buffer)
    (replace-regexp-entire-buffer "[ ]*{{dir\\(?:ectory\\)?_?\\(?:name\\)?\\(?:[0-9]+\\)}}[ ]*" "")
    (message "Save file to update list of TlDr errors")
  )
)

(defun tldr-correct-broken-ellipsis()
  "Replace {{placeholdernumber1}} {{placeholdernumber2}} ... placeholders with {{placeholdernumber1 placeholdernumber2 ...}} in the current buffer."
  (interactive)
  (with-current-buffer (current-buffer)
    (replace-regexp-entire-buffer "{{\\([^{}]+\\)[0-9]+}}\\([ ]+\\(?:{{\\1[0-9]+}}\\)\\)+" "{{\\11 \\12 ...}}")
    (message "Save file to update list of TlDr errors")
  )
)

(defun tldr-correct-broken-numbers()
  "Replace {{placeholder_number}} placeholders with {{placeholdernumber}} in the current buffer."
  (interactive)
  (with-current-buffer (current-buffer)
    (replace-regexp-entire-buffer "{{\\([^{}_]+\\)_+\\([0-9]+\\)}}" "{{\\1\\2}}")
    (message "Save file to update list of TlDr errors")
  )
)

(defun tldr-correct-broken-files()
  "Replace {{file}}, {{filename}}, and {{file_name}} placeholders with {{path/to/file}} in the current buffer.
Trailing numbers are respected too."
  (interactive)
  (with-current-buffer (current-buffer)
    (replace-regexp-entire-buffer "{{file_?\\(?:name\\)?\\([0-9]+\\)}}" "{{path/to/file\\1}}")
    (message "Save file to update list of TlDr errors")
  )
)

(defun tldr-correct-broken-directories()
  "Replace {{dir}}, {{dirname}}, {{dir_name}}, {{directory}}, {{directoryname}}, and {{directory_name}} placeholders with {{path/to/directory}} in the current buffer.
Trailing numbers are respected too."
  (interactive)
  (with-current-buffer (current-buffer)
    (replace-regexp-entire-buffer "{{dir\\(?:ectory\\)?_?\\(?:name\\)?\\([0-9]+\\)}}" "{{path/to/directory\\1}}")
    (message "Save file to update list of TlDr errors")
  )
)

(defun tldr-correct-broken-ranges()
  "Replace {{from-to}} placeholders with {{from..to}} in the current buffer.
If `from` or `to` is missing then it's replaced with negative or positive infinity respectively."
  (interactive)
  (with-current-buffer (current-buffer)
    (replace-regexp-entire-buffer "{{\\([0-9]+\\)-+\\([0-9]+\\)}}" "{{\\1..\\2}}")
    (replace-regexp-entire-buffer "{{-+\\([0-9]+\\)}}" "{{-infinity..\\1}}")
    (replace-regexp-entire-buffer "{{\\([0-9]+\\)-+}}" "{{\\1..infinity}}")
    (replace-regexp-entire-buffer "{{-+}}" "{{-infinity..infinity}}")
    (message "Save file to update list of TlDr errors")
  )
)

Support TLDR error ignorance via new custom option

Here is how I made it work in my ~/.emacs:

;;; flymake-tldr-lint.el --- A TlDr Flymake backend powered by tldr-lint  -*- lexical-binding: t; -*-
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)

(require 'flymake)

(defgroup flymake-tldr-lint nil
  "tldr-lint backend for Flymake."
  :prefix "flymake-tldr-lint-"
  :group 'tools)

(defcustom flymake-tldr-lint-program "tldr-lint"
  "The name of the `tldr-lint' executable."
  :type 'string)

(defcustom flymake-tldr-lint-ignored ""
  "Comma separated list of ignored errors."
  :type 'string)

(defvar-local flymake-tldr-lint--proc nil)

(defun flymake-tldr-lint--backend (report-fn &rest _args)
  "tldr-lint backend for Flymake.
Check for problems, then call REPORT-FN with results."
  (unless (executable-find flymake-tldr-lint-program)
    (error "Could not find tldr-lint executable"))

  (when (process-live-p flymake-tldr-lint--proc)
    (kill-process flymake-tldr-lint--proc)
    (setq flymake-tldr-lint--proc nil))

  (let* ((source (current-buffer))
	     (filename (buffer-file-name source)))
    (save-restriction
      (widen)
      (setq
       flymake-tldr-lint--proc
       (make-process
        :name "tldr-lint-flymake" :noquery t :connection-type 'pipe
        :buffer (generate-new-buffer " *tldr-lint-flymake*")
        :command (remove nil (list flymake-tldr-lint-program
                       filename))
        :sentinel
        (lambda (proc _event)
          (when (eq 'exit (process-status proc))
            (unwind-protect
                (if (with-current-buffer source (eq proc flymake-tldr-lint--proc))
                    (with-current-buffer (process-buffer proc)
                      (goto-char (point-min))
                      (cl-loop
                       while (search-forward-regexp
                              "^.+?:\\([0-9]+\\): \\(TLDR[0-9]+\\) \\(.*\\)$"
                              nil t)
                       for id = (match-string 2)
                       for msg = (match-string 3)
                       for (beg . end) = (flymake-diag-region
                                          source
                                          (string-to-number (match-string 1)) 1)
                       for type = :error
                       if (null (string-match (regexp-quote id) flymake-tldr-lint-ignored))
                       collect (flymake-make-diagnostic source
                                                        beg
                                                        end
                                                        type
                                                        (format "[%s] %s" id msg))
                       into diags
                       
                       finally (funcall report-fn diags)))
                  (flymake-log :warning "Canceling obsolete check %s"
                               proc))
              (kill-buffer (process-buffer proc))))))))))

;;;###autoload
(defun flymake-tldr-lint-load ()
  "Add the tldr-lint backend into Flymake's diagnostic functions list."
  (add-hook 'flymake-diagnostic-functions 'flymake-tldr-lint--backend nil t))

(provide 'flymake-tldr-lint)


(add-hook 'markdown-mode-hook 'flymake-tldr-lint-load)

(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(package-selected-packages '(markdown-mode)))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
)

This SO question helped me fix cl-loop to hide ignored errors.

Add snippets for generic placeholders

Add the following singular snippets:

  • f and file -> {{path/to/file}}
  • d and directory -> {{path/to/directory}}
  • fod and file_or_directory -> {{path/to/file_or_directory}}
  • a and argument -> {{argument}}
  • c and command -> {{command}}

Add the following plural snippets:

  • fs and files -> {{path/to/file1 path/to/file2 ...}}
  • ds and directories -> {{path/to/directory1 path/to/directory2 ...}}
  • fods and files_or_directories -> {{path/to/file_or_directory1 path/to/file_or_directory2 ...}}
  • as and arguments -> {{argument1 argument2 ...}}
  • cs and commands -> {{command1 command2 ...}}

Automatic mnemonic creation

Generate mnemonics for first occurrences of long/short options in descriptions. Letter case must be changed (now, but maybe later).

Implementation notes

Mnemonic generation is strictly textual, it doesn't understand term semantics so it can generate mnemonics in a wrong place (where letters from some option occur).

The best example for it is the following code:

- Print just a first line to `stdout`:                                                                                                                                                        
                                                                                                                                                                                              
`{{command}} | sed -n '1p'`

As already mentioned - function generating mnemonics doesn't know where it's more correct to add [n] mnemonic: to Print word or to line. By default (this behavior is not customizable now) it adds mnemonic to the first appropriate term, Print here: Pri[n]t.

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.