{"id":18391314,"url":"https://github.com/thblt/divine","last_synced_at":"2026-04-30T14:35:10.725Z","repository":{"id":68387277,"uuid":"246665678","full_name":"thblt/divine","owner":"thblt","description":"Modal editing for Emacs that feels like Emacs","archived":false,"fork":false,"pushed_at":"2021-05-05T18:30:29.000Z","size":277,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-16T01:25:26.813Z","etag":null,"topics":["emacs","modal","ui"],"latest_commit_sha":null,"homepage":"","language":"Emacs Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thblt.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-11T19:46:57.000Z","updated_at":"2021-05-05T18:30:32.000Z","dependencies_parsed_at":null,"dependency_job_id":"42c56be6-b929-47e8-86ac-30afafd55453","html_url":"https://github.com/thblt/divine","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thblt%2Fdivine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thblt%2Fdivine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thblt%2Fdivine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thblt%2Fdivine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thblt","download_url":"https://codeload.github.com/thblt/divine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248548343,"owners_count":21122678,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["emacs","modal","ui"],"created_at":"2024-11-06T01:51:27.538Z","updated_at":"2026-04-30T14:35:05.703Z","avatar_url":"https://github.com/thblt.png","language":"Emacs Lisp","funding_links":[],"categories":[],"sub_categories":[],"readme":"#+TITLE: Divine, a modal interface for Emacs with text objects (or something close enough)\n\n* Installation\n\nDivine isn't on Melpa (yet!).  Simply clone the repository somewhere\nin your =load-path=, and\n\n#+begin_src emacs-lisp\n  (require 'divine)\n#+end_src\n\nYou can now activate Divine for every buffer with =M-x\nglobal-divine-mode RET=, or for the current buffer only with =M-x\ndivine-mode RET=.  The global approach is the preferred way; Divine\nprovides facilities to customize its initial state per-buffer.\n\nThe simplest way to activate Divine is to add this to your init file:\n\n#+begin_src emacs-lisp\n  (divine-global-mode)\n#+end_src\n\nOr with use-package:\n\n#+begin_src emacs-lisp\n  (use-package divine\n     :init (divine-global-mode))\n#+end_src\n\n* Getting started\n\n** Basic motion\n\nBasic motion is very close to ordinary Emacs commands: =F= will go\nforward one character, =B= backward.  =f= and =b= will move forward\nand backward a word, respectively.\n\nWith =p= and =n=, you move to the previous\nand the next visible line, respectively.  =a= and =e= go to the\nbeginning and end of the current line, =A= end =E= move through\nsentences.\n\n=isearch= is on =s=, =r= for backwards.  =S= and =R= activate regexp\nsearch.\n\n** Operators\n\nLike Vim and other modal editors, Divine has operators.  Operators are\ncommands that act on a region.  Calling an operator with a non-empty\nregion active will execute immediately.  In normal mode, mark some\ntext (=m= toggles the mark) and press =d= to delete it.  If no region\nactive region exists, the operator becomes “pending” until the point\nmoves.  When the point has moved, it runs on the text range between\nthe previous and the new point position.\n\nHere's a very simple example, again with =d=, the deletion operator.\nIf you move to the end of a line and press =d=, the cursor starts\nblinking fast and “Pending” appears in the echo area.  Press =a= to go\nto the beginning of the line, and the line disappears (cancel with\n=u=).\n\nAll the basic operators have a “magic” motion that can be triggered by\npressing them twice: =dd= kills the current line, =cc= does the same,\nbut enters insert mode immediately after, =ww= copies it to the\nkill-ring, and so on.\n\n| Default binding | Action                                             |\n|-----------------+----------------------------------------------------|\n| =c= (change)    | Kill REGION to REGISTER then switch to insert mode |\n| =d= (delete)    | Kill REGION to REGISTER                            |\n| =w= (delete)    | Copy REGION to REGISTER                            |\n| =SPC w=         | Wrap REGION (prompt for char)                      |\n\nREGISTER defaults to the kill-ring.\n\n** Text objects\n\nText objects are motion commands that set both the point and the mark,\nand thus define a region.  There are two types of text objects: scoped\nmotions, which are motions that accept a scope modifier, and pure text\nobjects, which cannot be used as motions.\n\n*** Scoped motions\n\nDivine has two standard scopes: =around= and =inside=, activated by\n=a= and =i=, respectively.  Most basic motion commands respect these\nscopes, and behave as text objects when one is active.  For example,\n=di2w= will delete two full words, starting from the one the point's\non.  =da2w= will do the same, also eating the surrounding space.\n\n#+CAPTION: Standard scope selectors\n| =a= | Activate the =around= scope. |\n| =i= | Activate the =inside= scope. |\n\n*** Pure objects\n\nPure objects accept scope modifiers, but don't behave as motions even\nwithout one.  Divine has only one such object, =w=, which is the\nbalanced expression object.  It takes an extra parameter, which is the\ndelimiter to look for.  For example, =d2w(= will unwrap both\nparentheses around the second sexp around point.  =di2w(= will delete\ninside the sexp, and =da2w(= will also delete the parentheses.\n\n#+CAPTION: Standard pure text objects\n| =w= | Balanced expression around point1 |\n\n=w= is a *special object*.  Special objects can hot-replace a pending\noperator with their own implementation.  When called without a scope\nmodifier, =w= will hot-replace =divine-change= by =divine-rewrap=, and\n=divine-delete= by =divine-unwrap=.\n\n** Regions\n\nDivine has no equivalent to Vim's visual modes.  Instead, activating\nthe region with =m= modifies the behavior of some commands.  Operators\nrun immediately and most actions are disabled.\n\n| =M=             | Toggle region                |\n| =m=             | Toggle full lines only       |\n| =C-m=           | Toggle rectangular mark mode |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthblt%2Fdivine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthblt%2Fdivine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthblt%2Fdivine/lists"}