• Stars
    star
    284
  • Rank 144,484 (Top 3 %)
  • Language
    Emacs Lisp
  • License
    GNU General Publi...
  • Created almost 11 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Vim matchit ported into Emacs

evil-matchit

https://github.com/redguardtoo/evil-matchit/actions/workflows/test.yml/badge.svg https://elpa.nongnu.org/nongnu/evil-matchit.svg http://melpa.org/packages/evil-matchit-badge.svg http://stable.melpa.org/packages/evil-matchit-badge.svg

Vim matchit.vim by Benji Fisher is ported into Emacs.

Press “%” to jump between matched tags (“<div>” and “</div>” in html, etc).

Built-in supported languages and documents:

  • HTML
  • Python
  • Java
  • C++/C
  • Javascript
  • Typescript
  • React JSX (rjsx-mode, react-mode)
  • JSON
  • OCaml
  • Perl
  • Yaml
  • Latex
  • MATLAB/Octave
  • CMake
  • Markdown
  • Org (matching tags of other languages embedded in org file is also supported!)
  • Ruby
  • Elixir
  • Bash
  • Lua
  • PHP
  • Fortran
  • SQL
  • Laravel Blade Templating
  • Vim script
  • Verilog
  • Diff/Patch
  • Shell/Terminal bundled in Emacs
  • Emacs email (message-mode)
  • VCS (Git/Subversion/Perforce …) merge conflicts

If EVIL is installed, this package use EVIL as its vi layer.

If EVIL is not installed, most commands still work. So EVIL is only optional dependency.

Tested on Emacs 25, 26, 27, 28

Why use evil-matchit

  • Support any modern languages (html/java/c/c++/python/latex/javascript …)
  • Powerful. If you mix jsp, freemarker, html, jquery template or any weird syntax into one file, it still works!
  • Extendable. Write a plugin for it takes only 5 minutes

Screen cast for python: screencast.gif

Install

It’s already uploaded to http://melpa.org/.

Set up

EVIL is used

Insert below code into ~/.emacs to setup key bindings:

(global-evil-matchit-mode 1)

Alternatively, you can enable evil-matchit-mode along a major mode by adding turn-on-evil-matchit-mode to the mode hook.

EVIL is not used

No setup is required.

Usage

EVIL is used

You can press “%” or M-x evilmi-jump-items to jump between tag pair in normal mode or visual mode (you press “v” to switch to visual mode).

Please note evil-matchit is smart enough to detect the tag automatically.

Tag pair could be open/closed html tag, or character pair like “{}” “[]” “()”, or the single/double quote(s) at the two ends of the string.

Inner/outer text object “%” is also created. It roughly equals the region when you press “%” from evil-matchit.

Press “va%” to select line(s) wrapped by tags including tags themselves. M-x evilmi-select-items does the same thing.

Press “da%” to delete line(s) wrapped by tags including tags themselves. M-x evilmi-delete-items does the same thing.

All commands support numeric argument like “3%”, “5va%” or “9da%”

Pressing “3%” jumps to a line 3 percentage down the file. It’s the default behavior in original evil-mode. You can (setq evilmi-may-jump-by-percentage nil) to turn off this feature. Then “3%” will jump 3 times.

If you need visually select lines, you could use evilmi-select-items.

This is actually an advantage of Emacs, you can tweak the select region without go into visual state at all.

EVIL is not used

Use evilmi-jump-items-native to replace evilmi-jump-items. Evil text object “%” is de-activated.

But all the other commands like evilmi-delete-items and evilmi-select-items still work.

Tips

Toggle other modes before&after jumping to the matched tag

It’s reported some mode is not compatible with this package.

You can use evilmi-jump-hook to turn off the mode before jumping to the matched tag.

Then turn on it after the jump using the same hook.

Here is an example to toggle global-tree-sitter-mode,

(add-hook 'evilmi-jump-hook
          (lambda (before-jump-p)
            (global-tree-sitter-mode (not before-jump-p))))

Support new major modes

In order to apply three matching rules evilmi-template, evilmi-simple, and evilmi-html on mhtml-mode, please insert below code after your evil-matchit setup:

(evilmi-load-plugin-rules '(mhtml-mode) '(template simple html))

Use evilmi-select-items instead press “%” in evil-visual-state

evilmi-select-items is more robust and provides more functionality. It works even when evil-mode is not loaded.

So you’d better stick to evilmi-select-item if possible.

Add new tags into existing languages

Use ruby as an example.

If you want to add more tags into ruby, you can do two things:

  • You need define the regular expression to extract keyword
  • You need define the open/middle/closed tags

Open evil-matchit-ruby.el whole structure is like,

(defvar evilmi-ruby-extract-keyword-howtos '())
(defvar evilmi-ruby-match-tags '())
;; more code here ...
(provide 'evil-matchit-ruby)

So you configuration in ~/.emacs is as below:

(with-eval-after-load "evil-matchit-ruby"
  (push '("^[ \t]*\\([a-z]+\\)\\( .*\\| *\\)$" 1) evilmi-ruby-extract-keyword-howtos)
  (push '(("unless" "if") ("elsif" "else") "end")) evilmi-ruby-match-tags)

Re-define keybinding

All you need to do is to define function evilmi-customize-keybinding before turning on evil-matchit-mode:

The shortcut % is defined in evilmi-shortcut. It’s the name of text object and shortcut of evilmi-jump-items. Some people prefer set it to “m”.

Change keybinding of evilmi-jump-items and name of the text object,

(setq evilmi-shortcut "m")
(global-evil-matchit-mode 1)

Change keybinding only,

(defun evilmi-customize-keybinding ()
  (evil-define-key 'normal evil-matchit-mode-map
    "%" 'evilmi-jump-items))
(global-evil-matchit-mode 1)

Jump between the two end of the “string”

Please note the definition of “string” could be customized by user.

For example, we could treat C comment as string wrapper by “/”.

Here is the setup to jump between the two ends of the C comment:

(setq evilmi-quote-chars (string-to-list "'\"/"))

Match case-sensitive tags?

It’s decided by the Emacs global variable “case-fold-search”. You need not care about it because the major mode will set this flag automatically.

Python

You can turn on evilmi-always-simple-jump to match brackets at first.

Thus, you disable our advanced algorithm which I highly recommend.

Some people may prefer simpler algorithm in python-mode.

Developer guide

Quick start to support new language

Simple. You only need define two functions and tell evil-matchit in which major mode they should be used.

A complete setup to insert into “~/.emacs”:

;; detect tag in current line and return the result in variable rlt
;; the rlt will be used by evilmi-mylang-jump as the first parameter.
;; if NO tag found, the rlt SHOULD be nil
;;
;; @return the data to be used by evilmi-mylang-jump which should be a list
;;         the first element of the list is the position of cursor before jump
;;         we use it to select/delete tag. The other elements of the list could
;;         be any data type
(defun evilmi-mylang-get-tag ()
  (list position-of-open-end "anything-you-like" "anything-you-like"))

;; @parama rlt result from evilmi-mylang-get-tag
;; @param NUM numeric argument when user press "%" to match tag
;; @return the matching tag position in theory, useful only for
;;         selecting or deleting text between matching tags and tags
(defun evilmi-mylang-jump (info num)
  (message "info=%s" info)
  ;; if we need select region between tags (including tags itself)
  ;; we get the beginning of region by reading the first element of
  ;; info
  (push-mark (nth 0 info) t t)
  ;; say 999 is the where we jump to
  (goto-char 999)
  ;; If you need know where is the end of the region for region operation,
  ;; you need return the end of region at the end of function
  ;; region operation means selection/deletion of region.
  888)

;; Notify evil-matchit how to use above functions
(evilmi-load-plugin-rules '(mylang-mode) '(mylang))

Place above code into your ~/.emacs, after the line “(global-evil-matchit-mode 1)”

Use SDK

For example, it only takes 3 steps to create a new rule script to match tags in script like Ruby/Lua/Bash/VimScript,

Step 1, create evil-matchit-script.el,

(require 'evil-matchit-sdk)

;; ruby/bash/lua/vimrc
(defvar evilmi-script-match-tags
  '((("unless" "if") ("elif" "elsif" "elseif" "else") ( "end" "fi" "endif"))
    ("begin" ("rescue" "ensure") "end")
    ("case" ("when" "else") ("esac" "end"))
    (("fun!" "function!" "class" "def" "while" "function" "do") () ("end" "endfun" "endfunction"))
    ("repeat" ()  "until"))
  "The table we look up match tags. This is a three column table.
The first column contains the open tag(s).
The second column contains the middle tag(s).
The third column contains the closed tags(s).
The forth *optional* column defines the relationship between open and close tags. It could be MONOGAMY
")

;;;###autoload
(defun evilmi-script-get-tag ()
  (evilmi-sdk-get-tag evilmi-script-match-tags
                      evilmi-sdk-extract-keyword-howtos))

;;;###autoload
(defun evilmi-script-jump (rlt num)
  (evilmi-sdk-jump rlt
                   num
                   evilmi-script-match-tags
                   evilmi-sdk-extract-keyword-howtos))

(provide 'evil-matchit-script)

Step 2, make sure the directory of evil-matchit-script.el is added into load-path.

Step 3, add below code to ~/.emacs.,

(evilmi-load-plugin-rules '(ruby-mode lua-mode) '(script))

Support languages using indentation to identify a block of code

It’s easy to support such language (Python, Yaml, …).

Here is a minimum example to support yaml,

(require 'evil-matchit-indent)

(defun evilmi-yaml-get-tag ()
  (evilmi-indent-get-tag))

(defun evilmi-yaml-jump (info num)
  (let* ((evilmi-spaces-per-tab 2))
    (evilmi-indent-jump info)))

(evilmi-load-plugin-rules '(yaml-mode) '(yaml))

APIs

  • evilmi-load-plugin-rules

Contact me

Report bugs at https://github.com/redguardtoo/evil-matchit.

More Repositories

1

mastering-emacs-in-one-year-guide

Be great at emacs in one year
6,336
star
2

emacs.d

Fast and robust Emacs setup.
Emacs Lisp
2,385
star
3

find-file-in-project

Quick access to project files in Emacs
Emacs Lisp
424
star
4

evil-nerd-commenter

Comment/uncomment lines efficiently. Like Nerd Commenter in Vim
Emacs Lisp
385
star
5

elpa-mirror

Create local emacs package repository. 15 seconds to install 115 packages.
Emacs Lisp
308
star
6

cpputils-cmake

Easy real time C++ syntax check and intellisense if you use CMake
Emacs Lisp
195
star
7

counsel-etags

Fast, energy-saving, and powerful code navigation solution
Emacs Lisp
175
star
8

wucuo

Fastest solution to spell check camel case code or plain text
Emacs Lisp
120
star
9

eacl

eacl - Emacs auto complete lines by grepping project
Emacs Lisp
97
star
10

vc-msg

Show commit message of current line in Emacs
Emacs Lisp
75
star
11

cliphist

Paste from clipboard manager into Emacs
Emacs Lisp
75
star
12

js-comint

js-comint will send the code from Emacs into node.js or rhino
Emacs Lisp
68
star
13

company-ctags

Fastest Emacs auto-completion using Company and Ctags
Emacs Lisp
57
star
14

pyim-tsinghua-dict

用清华大学开放中文词库数据建立的pyim 输入法]词库. 已基于词频统计信息DF值(Document Frequency)优化
Python
47
star
15

mybigword

Use Zipf frequency of each word to extract English big words
Emacs Lisp
38
star
16

org2nikola

export org into html used by static blog generator like https://github.com/getnikola/nikola
Emacs Lisp
26
star
17

myelpa

Mirror of Emacs packages I'm using
23
star
18

vscode-setup

21
star
19

gmail2bbdb

convert gmail contacts to BBDB file, easy to use, robust, no dependency
Emacs Lisp
20
star
20

vscode-matchit

Jump between matching HTML tags and brackets smartly in VS Code. It's ported from Vim matchit by Benji Fisher
TypeScript
19
star
21

find-by-pinyin-dired

Find file by first Pinyin characters of Chinese Hanzi. 输入拼音首字母定位对应的中文目录/文件
Emacs Lisp
18
star
22

imenu-extra

Add extra items into lsp-mode/js2-mode imenu items
Emacs Lisp
15
star
23

redguardtoo.github.io

my blog
HTML
14
star
24

NinjaWebCoder

Use keyboard to copy code from stackoverflow
HTML
14
star
25

pyim2fcitx

Conver pyim dictionary to fcitx dictionary
Python
12
star
26

dianyou

Search/Analyze mails in Gnus
Emacs Lisp
12
star
27

test-git-mergetool

toy project to test git mergetool
12
star
28

lazyflymake

Lightweight syntax checker for Emacs, alternative of `flymake-mode'
Emacs Lisp
11
star
29

shellcop

Analyze errors reported in Emacs builtin shell
Emacs Lisp
10
star
30

evil-mark-replace

replace string in marked region effectively
Emacs Lisp
9
star
31

counsel-bbdb

Quick search&input email from BBDB based on ivy
Emacs Lisp
9
star
32

js2hl

Highlight/rename things using `js2-mode' parser
Emacs Lisp
8
star
33

shenshou

download subtitles from opensubtitles.org
Emacs Lisp
8
star
34

spell-check-code-in-ci

Free and powerful solution to spell check code at Continuous integration server
Makefile
7
star
35

fastdef

Insert terminology faster
Emacs Lisp
6
star
36

diff-lisp

Diff files&strings in pure Emacs Lisp.
Emacs Lisp
6
star
37

root-dotfiles

my dotfiles as root at Linux host
Shell
6
star
38

jqcuo

Powerful and simple solution to spell check code in command line
Emacs Lisp
6
star
39

jest-coverage-for-files-outside-of-root

jest coverage for files outside of root
JavaScript
5
star
40

find-and-ctags

Use `find' and `ctags' for code navigation
Emacs Lisp
5
star
41

portable-percol

portable percol (https://github.com/mooz/percol)
Python
5
star
42

zhfreq

processing chinese text using word frequency data
Emacs Lisp
4
star
43

my-emacs.d-snapshot

Emacs Lisp
4
star
44

AX88772C_Source

my usb to net adapter
C
4
star
45

test-git-blame

A project to test git blame
JavaScript
3
star
46

roblox-mode

Emacs major mode to edit Roblox Studio rbxlx files
Emacs Lisp
3
star
47

org-mime

org html export for text/html MIME emails
3
star
48

perl-recordmydesktop

perl-recordmydesktop.pl is the frontend for recordMyDesktop screencast tool
Prolog
3
star
49

counsel-ctags

Fast code navigation using Universal Ctags
Emacs Lisp
3
star
50

test-git-log

JavaScript
1
star
51

asus-pce-n53-11n-n600

ASUS PCE-N53 wireless patched driver and gentoo installation mini-guide
C
1
star
52

ms-frontend-sandbox

sandbox for interviewers
JavaScript
1
star
53

helloworld

hello world
C
1
star
54

wxwidgets-help

Look up wxWidgets API in Emacs by using local html manual
Emacs Lisp
1
star