mirror of
https://gitlab.com/dwt1/dotfiles.git
synced 2026-04-23 03:20:26 +10:00
Moving to Doom Emacs!
This commit is contained in:
66
.emacs.d/modules/app/calendar/README.org
Normal file
66
.emacs.d/modules/app/calendar/README.org
Normal file
@@ -0,0 +1,66 @@
|
||||
#+TITLE: app/calendar
|
||||
#+DATE: January 13, 2018
|
||||
#+SINCE: v2.1
|
||||
#+STARTUP: inlineimages
|
||||
|
||||
* Table of Contents :TOC:
|
||||
- [[#description][Description]]
|
||||
- [[#module-flags][Module Flags]]
|
||||
- [[#packages][Packages]]
|
||||
- [[#configuration][Configuration]]
|
||||
- [[#changing-calendar-sources][Changing calendar sources]]
|
||||
- [[#synchronizing-org-and-google-calendar][Synchronizing Org and Google Calendar]]
|
||||
|
||||
* Description
|
||||
This module adds a calendar view for Emacs, with org and google calendar sync
|
||||
support.
|
||||
|
||||
** Module Flags
|
||||
This module provides no flags.
|
||||
|
||||
** Packages
|
||||
+ [[https://github.com/kiwanami/emacs-calfw][calfw]]
|
||||
+ [[https://github.com/kiwanami/emacs-calfw][calfw-org]]
|
||||
+ [[https://github.com/myuhe/org-gcal.el][org-gcal]]
|
||||
|
||||
* Configuration
|
||||
** Changing calendar sources
|
||||
By defining your own calendar commands, you can control what sources to pull
|
||||
calendar data from:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun my-open-calendar ()
|
||||
(interactive)
|
||||
(cfw:open-calendar-buffer
|
||||
:contents-sources
|
||||
(list
|
||||
(cfw:org-create-source "Green") ; orgmode source
|
||||
(cfw:howm-create-source "Blue") ; howm source
|
||||
(cfw:cal-create-source "Orange") ; diary source
|
||||
(cfw:ical-create-source "Moon" "~/moon.ics" "Gray") ; ICS source1
|
||||
(cfw:ical-create-source "gcal" "https://..../basic.ics" "IndianRed") ; google calendar ICS
|
||||
)))
|
||||
#+END_SRC
|
||||
|
||||
To control what org files ~clfw:org-create-source~ will use, ~let~-bind
|
||||
~org-agenda-files~ around a call to ~+calendar/open-calendar~ like so:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
;;;###autoload
|
||||
(defun cfw:open-org-calendar-with-cal1 ()
|
||||
(interactive)
|
||||
(let ((org-agenda-files '("/path/to/org/" "/path/to/cal1.org")))
|
||||
(call-interactively #'+calendar/open-calendar)))
|
||||
|
||||
;;;###autoload
|
||||
(defun cfw:open-org-calendar-with-cal2 ()
|
||||
(interactive)
|
||||
(let ((org-agenda-files '("/path/to/org/" "/path/to/cal2.org")))
|
||||
(call-interactively #'+calendar/open-calendar)))
|
||||
#+END_SRC
|
||||
|
||||
The [[https://github.com/kiwanami/emacs-calfw][kiwanami/emacs-calfw]] project readme contains more examples.
|
||||
|
||||
** Synchronizing Org and Google Calendar
|
||||
The [[https://github.com/myuhe/org-gcal.el][myuhe/org-gcal.el]] project README contains more detailed instructions on how
|
||||
to link your calendar with Google calendars.
|
||||
61
.emacs.d/modules/app/calendar/autoload.el
Normal file
61
.emacs.d/modules/app/calendar/autoload.el
Normal file
@@ -0,0 +1,61 @@
|
||||
;;; app/calendar/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +calendar--wconf nil)
|
||||
|
||||
(defun +calendar--init ()
|
||||
(if-let* ((win (cl-loop for win in (doom-visible-windows)
|
||||
if (string-match-p "^\\*cfw:" (buffer-name (window-buffer win)))
|
||||
return win)))
|
||||
(select-window win)
|
||||
(call-interactively +calendar-open-function)))
|
||||
|
||||
;;;###autoload
|
||||
(defun =calendar ()
|
||||
"Activate (or switch to) `calendar' in its workspace."
|
||||
(interactive)
|
||||
(if (featurep! :ui workspaces)
|
||||
(progn
|
||||
(+workspace-switch "Calendar" t)
|
||||
(doom/switch-to-scratch-buffer)
|
||||
(+calendar--init)
|
||||
(+workspace/display))
|
||||
(setq +calendar--wconf (current-window-configuration))
|
||||
(delete-other-windows)
|
||||
(switch-to-buffer (doom-fallback-buffer))
|
||||
(+calendar--init)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +calendar/quit ()
|
||||
"TODO"
|
||||
(interactive)
|
||||
(if (featurep! :ui workspaces)
|
||||
(+workspace/delete "Calendar")
|
||||
(doom-kill-matching-buffers "^\\*cfw:")
|
||||
(set-window-configuration +calendar--wconf)
|
||||
(setq +calendar--wconf nil)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +calendar/open-calendar ()
|
||||
"TODO"
|
||||
(interactive)
|
||||
(cfw:open-calendar-buffer
|
||||
;; :custom-map cfw:my-cal-map
|
||||
:contents-sources
|
||||
(list
|
||||
(cfw:org-create-source (face-foreground 'default)) ; orgmode source
|
||||
)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +calendar-cfw:render-button-a (title command &optional state)
|
||||
"render-button
|
||||
TITLE
|
||||
COMMAND
|
||||
STATE"
|
||||
(let ((text (concat " " title " "))
|
||||
(keymap (make-sparse-keymap)))
|
||||
(cfw:rt text (if state 'cfw:face-toolbar-button-on
|
||||
'cfw:face-toolbar-button-off))
|
||||
(define-key keymap [mouse-1] command)
|
||||
(cfw:tp text 'keymap keymap)
|
||||
(cfw:tp text 'mouse-face 'highlight)
|
||||
text))
|
||||
51
.emacs.d/modules/app/calendar/config.el
Normal file
51
.emacs.d/modules/app/calendar/config.el
Normal file
@@ -0,0 +1,51 @@
|
||||
;;; app/calendar/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +calendar-open-function #'+calendar/open-calendar
|
||||
"TODO")
|
||||
|
||||
|
||||
;;
|
||||
;; Packages
|
||||
|
||||
(use-package! calfw
|
||||
:commands cfw:open-calendar-buffer
|
||||
:config
|
||||
;; better frame for calendar
|
||||
(setq cfw:face-item-separator-color nil
|
||||
cfw:render-line-breaker 'cfw:render-line-breaker-none
|
||||
cfw:fchar-junction ?╋
|
||||
cfw:fchar-vertical-line ?┃
|
||||
cfw:fchar-horizontal-line ?━
|
||||
cfw:fchar-left-junction ?┣
|
||||
cfw:fchar-right-junction ?┫
|
||||
cfw:fchar-top-junction ?┯
|
||||
cfw:fchar-top-left-corner ?┏
|
||||
cfw:fchar-top-right-corner ?┓)
|
||||
|
||||
(define-key cfw:calendar-mode-map "q" #'+calendar/quit)
|
||||
|
||||
(add-hook 'cfw:calendar-mode-hook #'doom-mark-buffer-as-real-h)
|
||||
(add-hook 'cfw:calendar-mode-hook 'hide-mode-line-mode)
|
||||
|
||||
(advice-add #'cfw:render-button :override #'+calendar-cfw:render-button-a))
|
||||
|
||||
|
||||
(use-package! calfw-org
|
||||
:commands (cfw:open-org-calendar
|
||||
cfw:org-create-source
|
||||
cfw:open-org-calendar-withkevin
|
||||
my-open-calendar))
|
||||
|
||||
|
||||
(use-package! org-gcal
|
||||
:commands (org-gcal-sync
|
||||
org-gcal-fetch
|
||||
org-gcal-post-at-point
|
||||
org-gcal-delete-at-point)
|
||||
:config
|
||||
;; hack to avoid the deferred.el error
|
||||
(defun org-gcal--notify (title mes)
|
||||
(message "org-gcal::%s - %s" title mes)))
|
||||
|
||||
|
||||
;; (use-package! alert)
|
||||
6
.emacs.d/modules/app/calendar/packages.el
Normal file
6
.emacs.d/modules/app/calendar/packages.el
Normal file
@@ -0,0 +1,6 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; app/calendar/packages.el
|
||||
|
||||
(package! calfw)
|
||||
(package! calfw-org)
|
||||
(package! org-gcal)
|
||||
141
.emacs.d/modules/app/irc/README.org
Normal file
141
.emacs.d/modules/app/irc/README.org
Normal file
@@ -0,0 +1,141 @@
|
||||
#+TITLE: app/irc
|
||||
#+DATE: June 11, 2017
|
||||
#+SINCE: v2.0.3
|
||||
#+STARTUP: inlineimages
|
||||
|
||||
* Table of Contents :TOC:
|
||||
- [[#description][Description]]
|
||||
- [[#module-flags][Module Flags]]
|
||||
- [[#plugins][Plugins]]
|
||||
- [[#dependencies][Dependencies]]
|
||||
- [[#prerequisites][Prerequisites]]
|
||||
- [[#features][Features]]
|
||||
- [[#an-irc-client-in-emacs][An IRC Client in Emacs]]
|
||||
- [[#configuration][Configuration]]
|
||||
- [[#pass-the-unix-password-manager][Pass: the unix password manager]]
|
||||
- [[#emacs-auth-source-api][Emacs' auth-source API]]
|
||||
- [[#troubleshooting][Troubleshooting]]
|
||||
|
||||
* Description
|
||||
This module turns adds an IRC client to Emacs with OS notifications.
|
||||
|
||||
** Module Flags
|
||||
This module provides no flags.
|
||||
|
||||
** Plugins
|
||||
+ [[https://github.com/jorgenschaefer/circe][circe]]
|
||||
+ [[https://github.com/eqyiel/circe-notifications][circe-notifications]]
|
||||
|
||||
* Dependencies
|
||||
This module requires =gnutls-cli= or =openssl= for secure connections.
|
||||
|
||||
* Prerequisites
|
||||
This module has no direct prerequisites.
|
||||
|
||||
* Features
|
||||
** An IRC Client in Emacs
|
||||
To connect to IRC you can invoke the ~=irc~ function using =M-x= or your own
|
||||
custom keybinding.
|
||||
|
||||
| command | description |
|
||||
|---------+-------------------------------------------|
|
||||
| ~=irc~ | Connect to IRC and all configured servers |
|
||||
|
||||
When in a circe buffer these keybindings will be available.
|
||||
|
||||
| command | key | description |
|
||||
|-----------------------------+-----------+----------------------------------------------|
|
||||
| ~+irc/tracking-next-buffer~ | =SPC m a= | Switch to the next active buffer |
|
||||
| ~circe-command-JOIN~ | =SPC m j= | Join a channel |
|
||||
| ~+irc/send-message~ | =SPC m m= | Send a private message |
|
||||
| ~circe-command-NAMES~ | =SPC m n= | List the names of the current channel |
|
||||
| ~circe-command-PART~ | =SPC m p= | Part the current channel |
|
||||
| ~+irc/quit~ | =SPC m Q= | Kill the current circe session and workgroup |
|
||||
| ~circe-reconnect~ | =SPC m R= | Reconnect the current server |
|
||||
|
||||
* Configuration
|
||||
Use ~set-irc-server!~ to configure IRC servers. Its second argument (a plist)
|
||||
takes the same arguments as ~circe-network-options~.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(set-irc-server! "chat.freenode.net"
|
||||
`(:tls t
|
||||
:nick "doom"
|
||||
:sasl-username "myusername"
|
||||
:sasl-password "mypassword"
|
||||
:channels ("#emacs")))
|
||||
#+END_SRC
|
||||
|
||||
*It is a obviously a bad idea to store auth-details in plaintext,* so here are
|
||||
some ways to avoid that:
|
||||
|
||||
** Pass: the unix password manager
|
||||
[[https://www.passwordstore.org/][Pass]] is my tool of choice. I use it to manage my passwords. If you activate the
|
||||
[[../../../modules/tools/pass/README.org][:tools pass]] module you get an elisp API through which to access your
|
||||
password store.
|
||||
|
||||
~set-irc-server!~ accepts a plist can use functions instead of strings.
|
||||
~+pass-get-user~ and ~+pass-get-secret~ can help here:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(set-irc-server! "chat.freenode.net"
|
||||
`(:tls t
|
||||
:nick "doom"
|
||||
:sasl-username ,(+pass-get-user "irc/freenode.net")
|
||||
:sasl-password ,(+pass-get-secret "irc/freenode.net")
|
||||
:channels ("#emacs")))
|
||||
#+END_SRC
|
||||
|
||||
But wait, there's more! This stores your password in a public variable which
|
||||
could be accessed or appear in backtraces. Not good! So we go a step further:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(set-irc-server! "chat.freenode.net"
|
||||
`(:tls t
|
||||
:port 6697
|
||||
:nick "doom"
|
||||
:sasl-username ,(+pass-get-user "irc/freenode.net")
|
||||
:sasl-password (lambda (&rest _) (+pass-get-secret "irc/freenode.net"))
|
||||
:channels ("#emacs")))
|
||||
#+END_SRC
|
||||
|
||||
And you're good to go!
|
||||
|
||||
Note that =+pass-get-user= tries to find your username by looking for the fields
|
||||
listed in =+pass-user-fields= (by default =login=, =user==, =username== and
|
||||
=email=)=). An example configuration looks like
|
||||
|
||||
#+BEGIN_SRC txt :tangle no
|
||||
mysecretpassword
|
||||
username: myusername
|
||||
#+END_SRC
|
||||
|
||||
** Emacs' auth-source API
|
||||
~auth-source~ is built into Emacs. As suggested [[https://github.com/jorgenschaefer/circe/wiki/Configuration#safer-password-management][in the circe wiki]], you can store
|
||||
(and retrieve) encrypted passwords with it.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(setq auth-sources '("~/.authinfo.gpg"))
|
||||
|
||||
(defun my-fetch-password (&rest params)
|
||||
(require 'auth-source)
|
||||
(let ((match (car (apply #'auth-source-search params))))
|
||||
(if match
|
||||
(let ((secret (plist-get match :secret)))
|
||||
(if (functionp secret)
|
||||
(funcall secret)
|
||||
secret))
|
||||
(error "Password not found for %S" params))))
|
||||
|
||||
(defun my-nickserv-password (server)
|
||||
(my-fetch-password :user "forcer" :host "irc.freenode.net"))
|
||||
|
||||
(set-irc-server! "chat.freenode.net"
|
||||
'(:tls t
|
||||
:port 6697
|
||||
:nick "doom"
|
||||
:sasl-password my-nickserver-password
|
||||
:channels ("#emacs")))
|
||||
#+END_SRC
|
||||
|
||||
* TODO Troubleshooting
|
||||
123
.emacs.d/modules/app/irc/autoload/irc.el
Normal file
123
.emacs.d/modules/app/irc/autoload/irc.el
Normal file
@@ -0,0 +1,123 @@
|
||||
;;; app/irc/autoload/email.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +irc--workspace-name "*IRC*")
|
||||
|
||||
(defun +irc-setup-wconf (&optional inhibit-workspace)
|
||||
(unless inhibit-workspace
|
||||
(+workspace-switch +irc--workspace-name t))
|
||||
(let ((buffers (doom-buffers-in-mode 'circe-mode nil t)))
|
||||
(if buffers
|
||||
(ignore (switch-to-buffer (car buffers)))
|
||||
(require 'circe)
|
||||
(delete-other-windows)
|
||||
(switch-to-buffer (doom-fallback-buffer))
|
||||
t)))
|
||||
|
||||
;;;###autoload
|
||||
(defun =irc (&optional inhibit-workspace)
|
||||
"Connect to IRC and auto-connect to all registered networks.
|
||||
|
||||
If INHIBIT-WORKSPACE (the universal argument) is non-nil, don't spawn a new
|
||||
workspace for it."
|
||||
(interactive "P")
|
||||
(cond ((and (featurep! :ui workspaces)
|
||||
(+workspace-exists-p +irc--workspace-name))
|
||||
(+workspace-switch +irc--workspace-name))
|
||||
((not (+irc-setup-wconf inhibit-workspace))
|
||||
(user-error "Couldn't start up a workspace for IRC")))
|
||||
(if (doom-buffers-in-mode 'circe-mode (buffer-list) t)
|
||||
(message "Circe buffers are already open")
|
||||
(if circe-network-options
|
||||
(cl-loop for network in circe-network-options
|
||||
collect (circe (car network)))
|
||||
(call-interactively #'circe))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +irc/connect (&optional inhibit-workspace)
|
||||
"Connect to a specific registered server.
|
||||
|
||||
If INHIBIT-WORKSPACE (the universal argument) is non-nil, don't spawn a new
|
||||
workspace for it."
|
||||
(interactive "P")
|
||||
(and (+irc-setup-wconf inhibit-workspace)
|
||||
(call-interactively #'circe)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +irc/send-message (who what)
|
||||
"Send WHO a message containing WHAT."
|
||||
(interactive "sWho: \nsWhat: ")
|
||||
(circe-command-MSG who what))
|
||||
|
||||
;;;###autoload
|
||||
(defun +irc/quit ()
|
||||
"Kill current circe session and workgroup."
|
||||
(interactive)
|
||||
(if (y-or-n-p "Really kill IRC session?")
|
||||
(let (circe-channel-killed-confirmation
|
||||
circe-server-killed-confirmation)
|
||||
(when +irc--defer-timer
|
||||
(cancel-timer +irc--defer-timer))
|
||||
(disable-circe-notifications)
|
||||
(mapc #'kill-buffer (doom-buffers-in-mode 'circe-mode (buffer-list) t))
|
||||
(when (equal (+workspace-current-name) +irc--workspace-name)
|
||||
(+workspace/delete +irc--workspace-name)))
|
||||
(message "Aborted")))
|
||||
|
||||
;;;###autoload
|
||||
(defun +irc/ivy-jump-to-channel (&optional this-server)
|
||||
"Jump to an open channel or server buffer with ivy. If THIS-SERVER (universal
|
||||
argument) is non-nil only show channels in current server."
|
||||
(interactive "P")
|
||||
(if (not (circe-server-buffers))
|
||||
(message "No circe buffers available")
|
||||
(when (and this-server (not circe-server-buffer))
|
||||
(setq this-server nil))
|
||||
(ivy-read (format "Jump to%s: " (if this-server (format " (%s)" (buffer-name circe-server-buffer)) ""))
|
||||
(cl-loop with servers = (if this-server (list circe-server-buffer) (circe-server-buffers))
|
||||
with current-buffer = (current-buffer)
|
||||
for server in servers
|
||||
collect (buffer-name server)
|
||||
nconc
|
||||
(with-current-buffer server
|
||||
(cl-loop for buf in (circe-server-chat-buffers)
|
||||
unless (eq buf current-buffer)
|
||||
collect (format " %s" (buffer-name buf)))))
|
||||
:action #'+irc--ivy-switch-to-buffer-action
|
||||
:preselect (buffer-name (current-buffer))
|
||||
:keymap ivy-switch-buffer-map
|
||||
:caller '+irc/ivy-jump-to-channel)))
|
||||
|
||||
(defun +irc--ivy-switch-to-buffer-action (buffer)
|
||||
(when (stringp buffer)
|
||||
(ivy--switch-buffer-action (string-trim-left buffer))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +irc/tracking-next-buffer ()
|
||||
"Dissables switching to an unread buffer unless in the irc workspace."
|
||||
(interactive)
|
||||
(when (derived-mode-p 'circe-mode)
|
||||
(tracking-next-buffer)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Hooks/fns
|
||||
|
||||
;;;###autoload
|
||||
(defun +circe-buffer-p (buf)
|
||||
"Return non-nil if BUF is a `circe-mode' buffer."
|
||||
(with-current-buffer buf
|
||||
(and (derived-mode-p 'circe-mode)
|
||||
(eq (safe-persp-name (get-current-persp))
|
||||
+irc--workspace-name))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +irc--add-circe-buffer-to-persp-h ()
|
||||
(when (bound-and-true-p persp-mode)
|
||||
(let ((persp (get-current-persp))
|
||||
(buf (current-buffer)))
|
||||
;; Add a new circe buffer to irc workspace when we're in another workspace
|
||||
(unless (eq (safe-persp-name persp) +irc--workspace-name)
|
||||
;; Add new circe buffers to the persp containing circe buffers
|
||||
(persp-add-buffer buf (persp-get-by-name +irc--workspace-name))
|
||||
;; Remove new buffer from accidental workspace
|
||||
(persp-remove-buffer buf persp)))))
|
||||
9
.emacs.d/modules/app/irc/autoload/settings.el
Normal file
9
.emacs.d/modules/app/irc/autoload/settings.el
Normal file
@@ -0,0 +1,9 @@
|
||||
;;; app/irc/autoload/settings.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autodef
|
||||
(defun set-irc-server! (server letvars)
|
||||
"Registers an irc SERVER for circe.
|
||||
|
||||
See `circe-network-options' for details."
|
||||
(after! circe
|
||||
(push (cons server letvars) circe-network-options)))
|
||||
235
.emacs.d/modules/app/irc/config.el
Normal file
235
.emacs.d/modules/app/irc/config.el
Normal file
@@ -0,0 +1,235 @@
|
||||
;;; app/irc/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +irc-left-padding 13
|
||||
"By how much spaces the left hand side of the line should be padded.
|
||||
Below a value of 12 this may result in uneven alignment between the various
|
||||
types of messages.")
|
||||
|
||||
(defvar +irc-truncate-nick-char ?…
|
||||
"Character to displayed when nick > `+irc-left-padding' in length.")
|
||||
|
||||
(defvar +irc-scroll-to-bottom-on-commands
|
||||
'(self-insert-command yank hilit-yank)
|
||||
"If these commands are called pre prompt the buffer will scroll to `point-max'.")
|
||||
|
||||
(defvar +irc-disconnect-hook nil
|
||||
"Runs each hook when circe noticies the connection has been disconnected.
|
||||
Useful for scenarios where an instant reconnect will not be successful.")
|
||||
|
||||
(defvar +irc-bot-list '("fsbot" "rudybot")
|
||||
"Nicks listed have `circe-fool-face' applied and will not be tracked.")
|
||||
|
||||
(defvar +irc-time-stamp-format "%H:%M"
|
||||
"The format of time stamps.
|
||||
|
||||
See `format-time-string' for a full description of available
|
||||
formatting directives. ")
|
||||
|
||||
(defvar +irc-notifications-watch-strings nil
|
||||
"A list of strings which can trigger a notification. You don't need to put
|
||||
your nick here.
|
||||
|
||||
See `circe-notifications-watch-strings'.")
|
||||
|
||||
(defvar +irc-defer-notifications nil
|
||||
"How long to defer enabling notifications, in seconds (e.g. 5min = 300).
|
||||
Useful for ZNC users who want to avoid the deluge of notifications during buffer
|
||||
playback.")
|
||||
|
||||
(defvar +irc--defer-timer nil)
|
||||
|
||||
(defsubst +irc--pad (left right)
|
||||
(format (format "%%%ds | %%s" +irc-left-padding)
|
||||
(concat "*** " left) right))
|
||||
|
||||
|
||||
;;
|
||||
;; Packages
|
||||
|
||||
(use-package! circe
|
||||
:commands circe circe-server-buffers
|
||||
:init (setq circe-network-defaults nil)
|
||||
:config
|
||||
(setq circe-default-quit-message nil
|
||||
circe-default-part-message nil
|
||||
circe-use-cycle-completion t
|
||||
circe-reduce-lurker-spam t
|
||||
|
||||
circe-format-say (format "{nick:+%ss} │ {body}" +irc-left-padding)
|
||||
circe-format-self-say circe-format-say
|
||||
circe-format-action (format "{nick:+%ss} * {body}" +irc-left-padding)
|
||||
circe-format-self-action circe-format-action
|
||||
circe-format-server-notice
|
||||
(let ((left "-Server-")) (concat (make-string (- +irc-left-padding (length left)) ? )
|
||||
(concat left " _ {body}")))
|
||||
circe-format-notice (format "{nick:%ss} _ {body}" +irc-left-padding)
|
||||
circe-format-server-topic
|
||||
(+irc--pad "Topic" "{userhost}: {topic-diff}")
|
||||
circe-format-server-join-in-channel
|
||||
(+irc--pad "Join" "{nick} ({userinfo}) joined {channel}")
|
||||
circe-format-server-join
|
||||
(+irc--pad "Join" "{nick} ({userinfo})")
|
||||
circe-format-server-part
|
||||
(+irc--pad "Part" "{nick} ({userhost}) left {channel}: {reason}")
|
||||
circe-format-server-quit
|
||||
(+irc--pad "Quit" "{nick} ({userhost}) left IRC: {reason}]")
|
||||
circe-format-server-quit-channel
|
||||
(+irc--pad "Quit" "{nick} ({userhost}) left {channel}: {reason}]")
|
||||
circe-format-server-rejoin
|
||||
(+irc--pad "Re-join" "{nick} ({userhost}), left {departuredelta} ago")
|
||||
circe-format-server-netmerge
|
||||
(+irc--pad "Netmerge" "{split}, split {ago} ago (Use /WL to see who's still missing)")
|
||||
circe-format-server-nick-change
|
||||
(+irc--pad "Nick" "{old-nick} ({userhost}) is now known as {new-nick}")
|
||||
circe-format-server-nick-change-self
|
||||
(+irc--pad "Nick" "You are now known as {new-nick} ({old-nick})")
|
||||
circe-format-server-nick-change-self
|
||||
(+irc--pad "Nick" "{old-nick} ({userhost}) is now known as {new-nick}")
|
||||
circe-format-server-mode-change
|
||||
(+irc--pad "Mode" "{change} on {target} by {setter} ({userhost})")
|
||||
circe-format-server-lurker-activity
|
||||
(+irc--pad "Lurk" "{nick} joined {joindelta} ago"))
|
||||
|
||||
(add-hook 'doom-real-buffer-functions #'+circe-buffer-p)
|
||||
(add-hook 'circe-channel-mode-hook #'turn-on-visual-line-mode)
|
||||
(add-hook 'circe-mode-hook #'+irc--add-circe-buffer-to-persp-h)
|
||||
|
||||
(defadvice! +irc--circe-run-disconnect-hook-a (&rest _)
|
||||
"Runs `+irc-disconnect-hook' after circe disconnects."
|
||||
:after #'circe--irc-conn-disconnected
|
||||
(run-hooks '+irc-disconnect-hook))
|
||||
|
||||
(add-hook! 'lui-pre-output-hook
|
||||
(defun +irc-circe-truncate-nicks-h ()
|
||||
"Truncate long nicknames in chat output non-destructively."
|
||||
(when-let (beg (text-property-any (point-min) (point-max) 'lui-format-argument 'nick))
|
||||
(goto-char beg)
|
||||
(let ((end (next-single-property-change beg 'lui-format-argument))
|
||||
(nick (plist-get (plist-get (text-properties-at beg) 'lui-keywords)
|
||||
:nick)))
|
||||
(when (> (length nick) +irc-left-padding)
|
||||
(compose-region (+ beg +irc-left-padding -1) end
|
||||
+irc-truncate-nick-char))))))
|
||||
|
||||
(add-hook! 'circe-message-option-functions
|
||||
(defun +irc-circe-message-option-bot-h (nick &rest ignored)
|
||||
"Fontify known bots and mark them to not be tracked."
|
||||
(when (member nick +irc-bot-list)
|
||||
'((text-properties . (face circe-fool-face lui-do-not-track t))))))
|
||||
|
||||
;; Let `+irc/quit' and `circe' handle buffer cleanup
|
||||
(define-key circe-mode-map [remap kill-buffer] #'bury-buffer)
|
||||
;; Fail gracefully if not in a circe buffer
|
||||
(global-set-key [remap tracking-next-buffer] #'+irc/tracking-next-buffer)
|
||||
|
||||
(map! :localleader
|
||||
(:map circe-mode-map
|
||||
"a" #'tracking-next-buffer
|
||||
"j" #'circe-command-JOIN
|
||||
"m" #'+irc/send-message
|
||||
"p" #'circe-command-PART
|
||||
"Q" #'+irc/quit
|
||||
"R" #'circe-reconnect
|
||||
(:when (featurep! :completion ivy)
|
||||
"c" #'+irc/ivy-jump-to-channel))
|
||||
(:map circe-channel-mode-map
|
||||
"n" #'circe-command-NAMES)))
|
||||
|
||||
|
||||
(use-package! circe-color-nicks
|
||||
:hook (circe-channel-mode . enable-circe-color-nicks)
|
||||
:config
|
||||
(setq circe-color-nicks-min-constrast-ratio 4.5
|
||||
circe-color-nicks-everywhere t))
|
||||
|
||||
|
||||
(use-package! circe-new-day-notifier
|
||||
:after circe
|
||||
:config
|
||||
(enable-circe-new-day-notifier)
|
||||
(setq circe-new-day-notifier-format-message
|
||||
(+irc--pad "Day" "Date changed [{day}]")))
|
||||
|
||||
|
||||
(use-package! circe-notifications
|
||||
:commands enable-circe-notifications
|
||||
:init
|
||||
(if +irc-defer-notifications
|
||||
(add-hook! 'circe-server-connected-hook
|
||||
(setq +irc--defer-timer
|
||||
(run-at-time +irc-defer-notifications nil
|
||||
#'enable-circe-notifications)))
|
||||
(add-hook 'circe-server-connected-hook #'enable-circe-notifications))
|
||||
:config
|
||||
(setq circe-notifications-watch-strings +irc-notifications-watch-strings
|
||||
circe-notifications-emacs-focused nil
|
||||
circe-notifications-alert-style
|
||||
(cond (IS-MAC 'osx-notifier)
|
||||
(IS-LINUX 'libnotify)
|
||||
(circe-notifications-alert-style))))
|
||||
|
||||
|
||||
(use-package! lui
|
||||
:commands lui-mode
|
||||
:config
|
||||
(define-key lui-mode-map "\C-u" #'lui-kill-to-beginning-of-line)
|
||||
(setq lui-fill-type nil)
|
||||
|
||||
(when (featurep! :tools flyspell)
|
||||
(setq lui-flyspell-p t))
|
||||
|
||||
(after! evil
|
||||
(defun +irc-evil-insert-h ()
|
||||
"Ensure entering insert mode will put us at the prompt, unless editing
|
||||
after prompt marker."
|
||||
(when (> (marker-position lui-input-marker) (point))
|
||||
(goto-char (point-max))))
|
||||
|
||||
(add-hook! 'lui-mode-hook
|
||||
(add-hook 'evil-insert-state-entry-hook #'+irc-evil-insert-h
|
||||
nil 'local))
|
||||
|
||||
(mapc (lambda (cmd) (push cmd +irc-scroll-to-bottom-on-commands))
|
||||
'(evil-paste-after evil-paste-before evil-open-above evil-open-below)))
|
||||
|
||||
|
||||
(defun +irc-preinput-scroll-to-bottom-h ()
|
||||
"Go to the end of the buffer in all windows showing it.
|
||||
Courtesy of esh-mode.el"
|
||||
(when (memq this-command +irc-scroll-to-bottom-on-commands)
|
||||
(let* ((selected (selected-window))
|
||||
(current (current-buffer)))
|
||||
(when (> (marker-position lui-input-marker) (point))
|
||||
(walk-windows
|
||||
(function
|
||||
(lambda (window)
|
||||
(when (eq (window-buffer window) current)
|
||||
(select-window window)
|
||||
(goto-char (point-max))
|
||||
(select-window selected))))
|
||||
nil t)))))
|
||||
|
||||
(add-hook! 'lui-mode-hook
|
||||
(add-hook 'pre-command-hook #'+irc-preinput-scroll-to-bottom-h nil t))
|
||||
|
||||
;; enable a horizontal line marking the last read message
|
||||
(add-hook 'lui-mode-hook #'enable-lui-track-bar)
|
||||
|
||||
(add-hook! 'lui-mode-hook
|
||||
(defun +irc-init-lui-margins-h ()
|
||||
(setq lui-time-stamp-position 'right-margin
|
||||
lui-time-stamp-format +irc-time-stamp-format
|
||||
right-margin-width (length (format-time-string lui-time-stamp-format))))
|
||||
(defun +irc-init-lui-wrapping-a ()
|
||||
(setq fringes-outside-margins t
|
||||
word-wrap t
|
||||
wrap-prefix (make-string (+ +irc-left-padding 3) ? )))))
|
||||
|
||||
|
||||
(use-package! lui-logging
|
||||
:after lui
|
||||
:config (enable-lui-logging))
|
||||
|
||||
|
||||
(use-package! lui-autopaste
|
||||
:hook (circe-channel-mode . enable-lui-autopaste))
|
||||
5
.emacs.d/modules/app/irc/packages.el
Normal file
5
.emacs.d/modules/app/irc/packages.el
Normal file
@@ -0,0 +1,5 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; app/irc/packages.el
|
||||
|
||||
(package! circe)
|
||||
(package! circe-notifications)
|
||||
14
.emacs.d/modules/app/regex/autoload/export.el
Normal file
14
.emacs.d/modules/app/regex/autoload/export.el
Normal file
@@ -0,0 +1,14 @@
|
||||
;;; app/regex/autoload/export.el
|
||||
|
||||
;;;###autoload
|
||||
(defun +regex/export () (interactive)) ; TODO +regex/export
|
||||
|
||||
|
||||
;;
|
||||
(defun +regex-export-python ()) ; import (re|regex)
|
||||
|
||||
(defun +regex-export-php ()) ; preg_(match(_all)?|replace)
|
||||
|
||||
(defun +regex-export-ruby ()) ; %r[.+]
|
||||
|
||||
(defun +regex-export-js ()) ; /.+/
|
||||
272
.emacs.d/modules/app/regex/autoload/regex.el
Normal file
272
.emacs.d/modules/app/regex/autoload/regex.el
Normal file
@@ -0,0 +1,272 @@
|
||||
;;; app/regex/autoload/regex.el
|
||||
|
||||
(defvar +regex--text-buffer nil)
|
||||
(defvar +regex--text-replace-buffer nil)
|
||||
(defvar +regex--expr-buffer nil)
|
||||
(defvar +regex--expr-replace-buffer nil)
|
||||
(defvar +regex--groups-buffer nil)
|
||||
(defvar +regex--replace-buffer nil)
|
||||
|
||||
;;
|
||||
(defface +regex-match-0-face
|
||||
`((t (:foreground "Black" :background ,(doom-color 'magenta) :bold t)))
|
||||
"TODO"
|
||||
:group 'faces)
|
||||
|
||||
(defface +regex-match-1-face
|
||||
`((t (:foreground "Black" :background ,(doom-color 'blue) :bold t)))
|
||||
"TODO"
|
||||
:group 'faces)
|
||||
|
||||
(defface +regex-match-2-face
|
||||
`((t (:foreground "Black" :background ,(doom-color 'green) :bold t)))
|
||||
"TODO"
|
||||
:group 'faces)
|
||||
|
||||
(defvar +regex-faces
|
||||
'(+regex-match-0-face +regex-match-1-face +regex-match-2-face)
|
||||
"TODO")
|
||||
|
||||
;;
|
||||
(defvar +regex-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map "\C-c\C-c" #'+regex-update-buffers)
|
||||
(define-key map "\C-c\C-r" #'=regex/replace)
|
||||
(define-key map "\C-c\C-k" #'+regex/quit)
|
||||
(define-key map [remap kill-current-buffer] #'+regex/quit)
|
||||
(define-key map [remap kill-buffer] #'+regex/quit)
|
||||
map)
|
||||
"TODO")
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode +regex-mode
|
||||
"TODO"
|
||||
:init-value nil
|
||||
:global nil
|
||||
:lighter ""
|
||||
:keymap +regex-mode-map
|
||||
(if +regex-mode
|
||||
(add-hook 'after-change-functions #'+regex-update-buffers nil t)
|
||||
(remove-hook 'after-change-functions #'+regex-update-buffers t)))
|
||||
|
||||
;;;###autoload
|
||||
(defun =regex (&optional dummy-text)
|
||||
"Start the Regex IDE."
|
||||
(interactive "P")
|
||||
(unless (buffer-live-p +regex--expr-buffer)
|
||||
(condition-case ex
|
||||
(progn
|
||||
(setq +regex--expr-buffer (get-buffer-create "*doom-regex*")
|
||||
+regex--text-buffer (if dummy-text (get-buffer-create "*doom-regex-text*") (current-buffer))
|
||||
+regex--groups-buffer (get-buffer-create "*doom-regex-groups*"))
|
||||
(when dummy-text
|
||||
(+workspace-switch +regex-workspace-name t)
|
||||
(switch-to-buffer +regex--text-buffer)
|
||||
(with-current-buffer +regex--text-buffer
|
||||
(insert +regex-dummy-text)))
|
||||
(pop-to-buffer +regex--groups-buffer)
|
||||
(pop-to-buffer +regex--expr-buffer)
|
||||
(with-current-buffer +regex--expr-buffer
|
||||
(conf-mode)
|
||||
(rainbow-delimiters-mode +1)
|
||||
(doom/toggle-line-numbers +1)
|
||||
(setq-local require-final-newline nil)
|
||||
(+regex-mode +1)
|
||||
(text-scale-set 3)))
|
||||
('error
|
||||
(+regex/quit)
|
||||
(error "Failed to open the Regexp IDE: %s" ex)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun =regex/replace ()
|
||||
(interactive)
|
||||
(unless (buffer-live-p +regex--replace-buffer)
|
||||
(let (text)
|
||||
(=regex t)
|
||||
(with-selected-window (get-buffer-window +regex--text-buffer)
|
||||
(setq text (buffer-string))
|
||||
(select-window (split-window-right))
|
||||
(switch-to-buffer (get-buffer-create "*doom-regex-text-repl*"))
|
||||
(erase-buffer)
|
||||
(insert text)
|
||||
(read-only-mode +1)
|
||||
(setq +regex--text-replace-buffer (current-buffer)))
|
||||
(with-current-buffer +regex--expr-buffer
|
||||
(select-window (split-window-right))
|
||||
(switch-to-buffer (get-buffer-create "*doom-regex-repl*"))
|
||||
(conf-mode)
|
||||
(rainbow-delimiters-mode +1)
|
||||
(doom/toggle-line-numbers -1)
|
||||
(setq-local require-final-newline nil)
|
||||
(setq mode-line-format nil
|
||||
+regex--expr-replace-buffer (current-buffer))
|
||||
(+regex-mode +1)
|
||||
(text-scale-set 3)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +regex/quit ()
|
||||
"TODO"
|
||||
(interactive)
|
||||
(when (and +regex--text-buffer (buffer-live-p +regex--text-buffer))
|
||||
(with-current-buffer +regex--text-buffer
|
||||
(+regex-mode -1)
|
||||
(remove-overlays nil nil 'category '+regex))
|
||||
(when (equal (buffer-name +regex--text-buffer) "*doom-regex-text*")
|
||||
(kill-buffer +regex--text-buffer)))
|
||||
(when (equal (+workspace-current-name) +regex-workspace-name)
|
||||
(+workspace/delete +regex-workspace-name))
|
||||
(mapc (lambda (bufname)
|
||||
(let ((buf (symbol-value bufname)))
|
||||
(when (and buf (buffer-live-p buf))
|
||||
(kill-buffer buf)
|
||||
(set bufname nil))))
|
||||
(list '+regex--text-replace-buffer
|
||||
'+regex--expr-replace-buffer
|
||||
'+regex--expr-buffer
|
||||
'+regex--groups-buffer
|
||||
'+regex--replace-buffer)))
|
||||
|
||||
(defun +regex--expr ()
|
||||
(when (buffer-live-p +regex--expr-buffer)
|
||||
(with-current-buffer +regex--expr-buffer
|
||||
(string-trim (buffer-string)))))
|
||||
|
||||
(defun +regex--expr-replace ()
|
||||
(when (buffer-live-p +regex--expr-replace-buffer)
|
||||
(with-current-buffer +regex--expr-replace-buffer
|
||||
(string-trim (buffer-string)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +regex-update-buffers (&optional beg end len)
|
||||
(interactive)
|
||||
(let* ((inhibit-read-only t)
|
||||
(regex (or (+regex--expr) ""))
|
||||
(replace (or (+regex--expr-replace) ""))
|
||||
(str (or (with-current-buffer +regex--text-buffer (buffer-string)) "")))
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(erase-buffer))
|
||||
(with-current-buffer +regex--text-buffer
|
||||
(remove-overlays nil nil 'category '+regex)
|
||||
(when (> (length regex) 0)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(pcase +regex-default-backend
|
||||
('emacs (+regex-backend-emacs regex replace str))
|
||||
('perl (+regex-backend-perl regex replace str))))))
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(goto-char (point-min)))))
|
||||
|
||||
|
||||
;; --- backends ---------------------------
|
||||
|
||||
(defun +regex--render-perl (regex text)
|
||||
"From <https://github.com/jwiegley/regex-tool>"
|
||||
(with-temp-buffer
|
||||
(insert (format "@lines = <DATA>;
|
||||
$line = join(\"\", @lines);
|
||||
print \"(\";
|
||||
while ($line =~ m/%s/gm) {
|
||||
print \"(\", length($`), \" \", length($&), \" \";
|
||||
for $i (1 .. 20) {
|
||||
if ($$i) {
|
||||
my $group = $$i;
|
||||
$group =~ s/([\\\\\"])/\\\\\\1/g;
|
||||
print \"(\", $i, \" . \\\"\", $group, \"\\\") \";
|
||||
}
|
||||
}
|
||||
print \")\";
|
||||
}
|
||||
print \")\";
|
||||
__DATA__
|
||||
%s" (replace-regexp-in-string "/" "\\/" regex nil t) text))
|
||||
(call-process-region (point-min) (point-max) "perl" t t)
|
||||
(goto-char (point-min))
|
||||
(read (current-buffer))))
|
||||
|
||||
(defun +regex--replace-perl (regex replace text)
|
||||
(unless (or (string-empty-p regex)
|
||||
(string-empty-p replace)
|
||||
(string-empty-p text))
|
||||
(with-temp-buffer
|
||||
(insert (format "@lines = <DATA>;
|
||||
$line = join(\"\", @lines);
|
||||
$line =~ s/%s/%s/gm;
|
||||
print $line;
|
||||
__DATA__
|
||||
%s" (replace-regexp-in-string "/" "\\/" regex nil t) (replace-regexp-in-string "/" "\\/" replace nil t) text))
|
||||
(call-process-region (point-min) (point-max) "perl" t t)
|
||||
(buffer-string))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +regex-backend-perl (regex replace str)
|
||||
"TODO"
|
||||
(cl-assert (stringp regex))
|
||||
(cl-assert (stringp replace))
|
||||
(cl-assert (stringp str))
|
||||
(let ((i 0)
|
||||
(results (+regex--render-perl regex str)))
|
||||
(when (buffer-live-p +regex--text-replace-buffer)
|
||||
(let ((replace (+regex--replace-perl regex replace str)))
|
||||
(with-current-buffer +regex--text-replace-buffer
|
||||
(erase-buffer)
|
||||
(insert
|
||||
(if (and (listp results)
|
||||
replace
|
||||
(not (string-empty-p replace)))
|
||||
replace
|
||||
str)))))
|
||||
(dolist (result (if (listp results) results))
|
||||
(let* ((offset (nth 0 result))
|
||||
(length (nth 1 result))
|
||||
(matches (nthcdr 2 result))
|
||||
(ov (make-overlay (1+ offset) (+ offset length 1))))
|
||||
(overlay-put ov 'face (nth (mod i 3) +regex-faces))
|
||||
(overlay-put ov 'category '+regex)
|
||||
(cl-incf i)
|
||||
(let* ((match-zero (buffer-substring (1+ offset) (+ offset length 1)))
|
||||
(line (format "Match: %s\n" (propertize match-zero 'face 'font-lock-string-face))))
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(insert line)))
|
||||
(dolist (match matches)
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(goto-char (point-max))
|
||||
(insert (format "Group %d: %s\n"
|
||||
(propertize (car match) 'face 'font-lock-constant-face)
|
||||
(propertize (cdr match) 'face 'font-lock-string-face)))))
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(insert ?\n))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +regex-backend-emacs (regex replace str)
|
||||
"TODO"
|
||||
(cl-assert (stringp regex))
|
||||
(cl-assert (stringp replace))
|
||||
(cl-assert (stringp str))
|
||||
(let ((i 0)
|
||||
pos)
|
||||
(when (buffer-live-p +regex--text-replace-buffer)
|
||||
(with-current-buffer +regex--text-replace-buffer
|
||||
(erase-buffer)
|
||||
(insert str)
|
||||
(when (and (listp results) (string-empty-p replace))
|
||||
(replace-regexp regex replace))))
|
||||
(while (and (setq pos (point))
|
||||
(re-search-forward regex nil t))
|
||||
(if (= (point) pos)
|
||||
(forward-char 1)
|
||||
(let ((ov (make-overlay (match-beginning 0) (match-end 0))))
|
||||
(overlay-put ov 'face (nth (mod i 3) +regex-faces))
|
||||
(overlay-put ov 'category '+regex))
|
||||
(cl-incf i)
|
||||
(dotimes (i 10)
|
||||
(when-let (text (match-string i))
|
||||
(save-match-data
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(goto-char (point-max))
|
||||
(insert
|
||||
(format "Group %d: %s\n"
|
||||
(propertize i 'face 'font-lock-constant-face)
|
||||
(propertize text 'face 'font-lock-string-face)))))))
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(insert ?\n))))))
|
||||
|
||||
51
.emacs.d/modules/app/regex/config.el
Normal file
51
.emacs.d/modules/app/regex/config.el
Normal file
@@ -0,0 +1,51 @@
|
||||
;;; app/regex/config.el
|
||||
|
||||
;; Often, I find myself writing regular expressions that could terrify seasoned
|
||||
;; programmers (or little children). To hone my regex fu, I need a regex
|
||||
;; playground. Sure, there's regexr.com, but don't be silly, that's not Emacs.
|
||||
;;
|
||||
;; Sadly, the Emacs' regex syntax is niche and lacks support for a few
|
||||
;; questionably useful features, like lookaround assertions, conditionals, case
|
||||
;; modifiers or backreferences, among others. No, I want PCRE. I am going to
|
||||
;; have my cake and eat it too, damn it!
|
||||
;;
|
||||
;; Workflow:
|
||||
;; + Invoke `=regex' (if opened with C-u, opens in separate workspace with a
|
||||
;; dummy text buffer).
|
||||
;; + A regex window will popup up. Any matches will be highlighted in the
|
||||
;; original buffer.
|
||||
;; + C-c C-k to close it
|
||||
;; + TODO C-c C-e to export to various langauges
|
||||
;;
|
||||
;; WARNING: THIS IS A WORK IN PROGRESS
|
||||
|
||||
(defvar +regex-workspace-name "*regex*"
|
||||
"TODO")
|
||||
|
||||
(defvar +regex-default-backend 'perl
|
||||
"The backend used to process regular expressions.
|
||||
The `emacs' backend handles regular expressions directly.
|
||||
The `perl' backend talks to a perl subprocess to do the handling.")
|
||||
|
||||
(defvar +regex-dummy-text
|
||||
"Welcome to DOOM Emacs, proudly hosted by the demons of hell!
|
||||
|
||||
Edit the Expression & Text to see matches. Roll over matches or the expression
|
||||
for details. Undo mistakes with ctrl-z. Save Favorites & Share expressions with
|
||||
friends or the Community. Explore your results with Tools. A full Reference &
|
||||
Help is available in the Library, or watch the video Tutorial.
|
||||
|
||||
Sample text for testing:
|
||||
abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
0123456789 _+-.,!@#$%^&*();\/|<>\"'
|
||||
12345 -98.7 3.141 .6180 9,000 +42
|
||||
555.123.4567 +1-(800)-555-2468
|
||||
foo@demo.net bar.ba@test.co.uk
|
||||
www.demo.com http://foo.co.uk/
|
||||
http://regexr.com/foo.html?q=bar
|
||||
https://mediatemple.net"
|
||||
"TODO")
|
||||
|
||||
(set-popup-rules!
|
||||
'(("^\\*doom-regex\\*$" :size 4 :quit nil)
|
||||
("^\\*doom-regex-groups" :side 'left :size 28 :select nil :quit nil)))
|
||||
117
.emacs.d/modules/app/rss/autoload.el
Normal file
117
.emacs.d/modules/app/rss/autoload.el
Normal file
@@ -0,0 +1,117 @@
|
||||
;;; app/rss/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defalias '=rss #'elfeed
|
||||
"Activate (or switch to) `elfeed' in its workspace.")
|
||||
|
||||
;;;###autoload
|
||||
(defun +rss/delete-pane ()
|
||||
"Delete the *elfeed-entry* split pane."
|
||||
(interactive)
|
||||
(let* ((buf (get-buffer "*elfeed-entry*"))
|
||||
(window (get-buffer-window buf)))
|
||||
(delete-window window)
|
||||
(when (buffer-live-p buf)
|
||||
(kill-buffer buf))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +rss/open (entry)
|
||||
"Display the currently selected item in a buffer."
|
||||
(interactive (list (elfeed-search-selected :ignore-region)))
|
||||
(when (elfeed-entry-p entry)
|
||||
(elfeed-untag entry 'unread)
|
||||
(elfeed-search-update-entry entry)
|
||||
(elfeed-show-entry entry)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +rss/next ()
|
||||
"Show the next item in the elfeed-search buffer."
|
||||
(interactive)
|
||||
(funcall elfeed-show-entry-delete)
|
||||
(with-current-buffer (elfeed-search-buffer)
|
||||
(forward-line)
|
||||
(call-interactively '+rss/open)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +rss/previous ()
|
||||
"Show the previous item in the elfeed-search buffer."
|
||||
(interactive)
|
||||
(funcall elfeed-show-entry-delete)
|
||||
(with-current-buffer (elfeed-search-buffer)
|
||||
(forward-line -1)
|
||||
(call-interactively '+rss/open)))
|
||||
|
||||
|
||||
;;
|
||||
;; Hooks
|
||||
|
||||
;;;###autoload
|
||||
(defun +rss-elfeed-wrap-h ()
|
||||
"Enhances an elfeed entry's readability by wrapping it to a width of
|
||||
`fill-column'."
|
||||
(let ((inhibit-read-only t)
|
||||
(inhibit-modification-hooks t))
|
||||
(setq-local truncate-lines nil)
|
||||
(setq-local shr-use-fonts nil)
|
||||
(setq-local shr-width 85)
|
||||
(set-buffer-modified-p nil)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +rss-cleanup-h ()
|
||||
"Clean up after an elfeed session. Kills all elfeed and elfeed-org files."
|
||||
(interactive)
|
||||
;; `delete-file-projectile-remove-from-cache' slows down `elfeed-db-compact'
|
||||
;; tremendously, so we disable the projectile cache:
|
||||
(let (projectile-enable-caching)
|
||||
(elfeed-db-compact))
|
||||
(let ((buf (previous-buffer)))
|
||||
(when (or (null buf) (not (doom-real-buffer-p buf)))
|
||||
(switch-to-buffer (doom-fallback-buffer))))
|
||||
(let ((search-buffers (doom-buffers-in-mode 'elfeed-search-mode))
|
||||
(show-buffers (doom-buffers-in-mode 'elfeed-show-mode))
|
||||
kill-buffer-query-functions)
|
||||
(dolist (file +rss-elfeed-files)
|
||||
(when-let (buf (get-file-buffer (expand-file-name file org-directory)))
|
||||
(kill-buffer buf)))
|
||||
(dolist (b search-buffers)
|
||||
(with-current-buffer b
|
||||
(remove-hook 'kill-buffer-hook #'+rss-cleanup-h :local)
|
||||
(kill-buffer b)))
|
||||
(mapc #'kill-buffer show-buffers)))
|
||||
|
||||
|
||||
;;
|
||||
;; Functions
|
||||
|
||||
;;;###autoload
|
||||
(defun +rss-dead-feeds (&optional years)
|
||||
"Return a list of feeds that haven't posted anything in YEARS."
|
||||
(let* ((years (or years 1.0))
|
||||
(living-feeds (make-hash-table :test 'equal))
|
||||
(seconds (* years 365.0 24 60 60))
|
||||
(threshold (- (float-time) seconds)))
|
||||
(with-elfeed-db-visit (entry feed)
|
||||
(let ((date (elfeed-entry-date entry)))
|
||||
(when (> date threshold)
|
||||
(setf (gethash (elfeed-feed-url feed) living-feeds) t))))
|
||||
(cl-loop for url in (elfeed-feed-list)
|
||||
unless (gethash url living-feeds)
|
||||
collect url)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +rss-put-sliced-image-fn (spec alt &optional flags)
|
||||
"TODO"
|
||||
(cl-letf (((symbol-function #'insert-image)
|
||||
(lambda (image &optional alt _area _slice)
|
||||
(let ((height (cdr (image-size image t))))
|
||||
(insert-sliced-image image alt nil (max 1 (/ height 20.0)) 1)))))
|
||||
(shr-put-image spec alt flags)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +rss-render-image-tag-without-underline-fn (dom &optional url)
|
||||
"TODO"
|
||||
(let ((start (point)))
|
||||
(shr-tag-img dom url)
|
||||
;; And remove underlines in case images are links, otherwise we get an
|
||||
;; underline beneath every slice.
|
||||
(put-text-property start (point) 'face '(:underline nil))))
|
||||
74
.emacs.d/modules/app/rss/config.el
Normal file
74
.emacs.d/modules/app/rss/config.el
Normal file
@@ -0,0 +1,74 @@
|
||||
;;; app/rss/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; This is an opinionated workflow that turns Emacs into an RSS reader, inspired
|
||||
;; by apps Reeder and Readkit. It can be invoked via `=rss'. Otherwise, if you
|
||||
;; don't care for the UI you can invoke elfeed directly with `elfeed'.
|
||||
|
||||
(defvar +rss-elfeed-files (list "elfeed.org")
|
||||
"Where to look for elfeed.org files, relative to `org-directory'. Can be
|
||||
absolute paths.")
|
||||
|
||||
(defvar +rss-split-direction 'below
|
||||
"What direction to pop up the entry buffer in elfeed.")
|
||||
|
||||
(defvar +rss-enable-sliced-images t
|
||||
"Automatically slice images shown in elfeed-show-mode buffers, making them
|
||||
easier to scroll through.")
|
||||
|
||||
|
||||
;;
|
||||
;; Packages
|
||||
|
||||
(use-package! elfeed
|
||||
:commands elfeed
|
||||
:config
|
||||
(setq elfeed-search-filter "@2-week-ago "
|
||||
elfeed-db-directory (concat doom-local-dir "elfeed/db/")
|
||||
elfeed-enclosure-default-dir (concat doom-local-dir "elfeed/enclosures/")
|
||||
elfeed-show-entry-switch #'pop-to-buffer
|
||||
elfeed-show-entry-delete #'+rss/delete-pane
|
||||
shr-max-image-proportion 0.8)
|
||||
|
||||
(set-popup-rule! "^\\*elfeed-entry"
|
||||
:size 0.75 :actions '(display-buffer-below-selected)
|
||||
:select t :quit nil :ttl t)
|
||||
|
||||
(make-directory elfeed-db-directory t)
|
||||
|
||||
;; Ensure elfeed buffers are treated as real
|
||||
(add-hook! 'doom-real-buffer-functions
|
||||
(defun +rss-buffer-p (buf)
|
||||
(string-match-p "^\\*elfeed" (buffer-name buf))))
|
||||
|
||||
;; Enhance readability of a post
|
||||
(add-hook 'elfeed-show-mode-hook #'+rss-elfeed-wrap-h)
|
||||
(add-hook! 'elfeed-search-mode-hook
|
||||
(add-hook 'kill-buffer-hook #'+rss-cleanup-h nil 'local))
|
||||
|
||||
;; Large images are annoying to scroll through, because scrolling follows the
|
||||
;; cursor, so we force shr to insert images in slices.
|
||||
(when +rss-enable-sliced-images
|
||||
(setq-hook! 'elfeed-show-mode-hook
|
||||
shr-put-image-function #'+rss-put-sliced-image-fn
|
||||
shr-external-rendering-functions '((img . +rss-render-image-tag-without-underline-fn))))
|
||||
|
||||
;; Keybindings
|
||||
(after! elfeed-show
|
||||
(define-key! elfeed-show-mode-map
|
||||
[remap next-buffer] #'+rss/next
|
||||
[remap previous-buffer] #'+rss/previous))
|
||||
(when (featurep! :editor evil +everywhere)
|
||||
(evil-define-key 'normal elfeed-search-mode-map
|
||||
"q" #'elfeed-kill-buffer
|
||||
"r" #'elfeed-search-update--force
|
||||
(kbd "M-RET") #'elfeed-search-browse-url)))
|
||||
|
||||
|
||||
(use-package! elfeed-org
|
||||
:when (featurep! +org)
|
||||
:after elfeed
|
||||
:config
|
||||
(let ((default-directory org-directory))
|
||||
(setq rmh-elfeed-org-files
|
||||
(mapcar #'expand-file-name +rss-elfeed-files)))
|
||||
(elfeed-org))
|
||||
5
.emacs.d/modules/app/rss/packages.el
Normal file
5
.emacs.d/modules/app/rss/packages.el
Normal file
@@ -0,0 +1,5 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; app/rss/packages.el
|
||||
|
||||
(package! elfeed)
|
||||
(package! elfeed-org)
|
||||
96
.emacs.d/modules/app/twitter/README.org
Normal file
96
.emacs.d/modules/app/twitter/README.org
Normal file
@@ -0,0 +1,96 @@
|
||||
#+TITLE: app/twitter
|
||||
#+DATE: October 11, 2019
|
||||
#+SINCE: v2.0
|
||||
#+STARTUP: inlineimages
|
||||
|
||||
* Table of Contents :TOC_3:noexport:
|
||||
- [[#description][Description]]
|
||||
- [[#module-flags][Module Flags]]
|
||||
- [[#plugins][Plugins]]
|
||||
- [[#hacks][Hacks]]
|
||||
- [[#prerequisites][Prerequisites]]
|
||||
- [[#features][Features]]
|
||||
- [[#configuration][Configuration]]
|
||||
- [[#troubleshooting][Troubleshooting]]
|
||||
- [[#appendix][Appendix]]
|
||||
- [[#commands--keybindings][Commands & Keybindings]]
|
||||
|
||||
* Description
|
||||
Enjoy twitter from emacs.
|
||||
|
||||
+ View various timelines side by side, e.g. user's timeline, home, etc.
|
||||
+ Post new tweets
|
||||
+ Send direct messages
|
||||
+ Retweet
|
||||
+ Follow and un-follow users
|
||||
+ Favorite tweets
|
||||
|
||||
** Module Flags
|
||||
This module provides no flags.
|
||||
|
||||
** Plugins
|
||||
+ [[https://github.com/hayamiz/twittering-mode][twittering-mode]]
|
||||
+ [[https://github.com/abo-abo/avy][avy]]
|
||||
|
||||
** TODO Hacks
|
||||
{A list of internal modifications to included packages}
|
||||
|
||||
* Prerequisites
|
||||
|
||||
+ For SSL connection (required by Twitter's API), one of the followings is required:
|
||||
+ [[http://curl.haxx.se/][cURL]]
|
||||
+ [[http://www.gnu.org/software/wget/][GNU Wget]]
|
||||
+ [[http://www.openssl.org/][OpenSSL]]
|
||||
+ [[http://www.gnu.org/software/gnutls/][GnuTLS]]
|
||||
+ [[http://www.gnupg.org/][GnuPG]] is required for keeping the OAuth token encrypted in local storage.
|
||||
+ ~twittering-icon-mode~ converts retrieved icons into XPM by default. To
|
||||
achieve this and for displaying icons in formats that are not supported by
|
||||
Emacs as well as for resizing icon images, [[http://www.imagemagick.org/][ImageMagick]] is required.
|
||||
|
||||
To build emacs with ImageMagick support the ~--with-imagemagick~ flag needs to
|
||||
be passed to the ~configure~ script, e.g. ~./configure --with-imagemagick~.
|
||||
For detailed instruction on how to build Emacs from source please refer to
|
||||
[[https://git.savannah.gnu.org/cgit/emacs.git/tree/INSTALL][INSTALL]] in Emacs' savannah repository.
|
||||
+ For keeping retrieved icons in local storage, [[http://www.gzip.org/][gzip]] is required.
|
||||
|
||||
* TODO Features
|
||||
An in-depth list of features, how to use them, and their dependencies.
|
||||
|
||||
* TODO Configuration
|
||||
How to configure this module, including common problems and how to address them.
|
||||
|
||||
* Troubleshooting
|
||||
Currently ~twittering-mode~ binds =SPC=, breaking its functionality as a leader
|
||||
key. To work around this issue you may use =M-SPC= instead when in
|
||||
~twittering-mode~.
|
||||
|
||||
* Appendix
|
||||
** Commands & Keybindings
|
||||
Here is a list of available commands and their default keybindings (defined in
|
||||
[[./config.el][config.el]]).
|
||||
|
||||
| command | key / ex command | description |
|
||||
|---------------------+------------------+-------------------------------------------------------------|
|
||||
| ~+twitter/quit~ | =q= | Close current window |
|
||||
| ~+twitter/quit-all~ | =Q= | Close all twitter windows and buffers, and delete workspace |
|
||||
|
||||
And when ~:editor evil +everywhere~ is active:
|
||||
|
||||
| command | key / ex command | description |
|
||||
|--------------------------------------------------+------------------+------------------------------------------------------------------|
|
||||
| ~twittering-favorite~ | =f= | Favorite/Like a tweet |
|
||||
| ~twittering-unfavorite~ | =F= | Un-favorite/Un-like a tweet |
|
||||
| ~twittering-follow~ | =C-f= | Follow user |
|
||||
| ~twittering-unfollow~ | =C-F= | Un-follow user |
|
||||
| ~twittering-delete-status~ | =d= | Delete a tweet |
|
||||
| ~twittering-retweet~ | =r= | Retweet |
|
||||
| ~twittering-toggle-or-retrieve-replied-statuses~ | =R= | Toggle or retrieve replies |
|
||||
| ~twittering-update-status-interactive~ | =o= | Update tweets |
|
||||
| ~+twitter/ace-link~ | =O= | Open some visible link from a ~twittering-mode~ buffer using ace |
|
||||
| ~twittering-search~ | =/= | Search |
|
||||
| ~twittering-goto-next-status~ | =J= | Go to next tweet |
|
||||
| ~twittering-goto-previous-status~ | =K= | Go to previous tweet |
|
||||
| ~twittering-goto-first-status~ | =gg= | Go to first tweet |
|
||||
| ~twittering-goto-last-status~ | =G= | Go to last tweet |
|
||||
| ~twittering-goto-next-status-of-user~ | =gj= | Go to next tweet of user |
|
||||
| ~twittering-goto-previous-status-of-user)))~ | =gk= | Go to previous tweet of user |
|
||||
103
.emacs.d/modules/app/twitter/autoload.el
Normal file
103
.emacs.d/modules/app/twitter/autoload.el
Normal file
@@ -0,0 +1,103 @@
|
||||
;;; app/twitter/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +twitter-workspace-name "*Twitter*"
|
||||
"The name to use for the twitter workspace.")
|
||||
|
||||
;;;###autoload
|
||||
(defun +twitter-display-buffer-fn (buf)
|
||||
"A replacement display-buffer command for `twittering-pop-to-buffer-function'
|
||||
that works with the feature/popup module."
|
||||
(let ((win (selected-window)))
|
||||
(display-buffer buf)
|
||||
;; This is required because the new window generated by `pop-to-buffer'
|
||||
;; may hide the region following the current position.
|
||||
(twittering-ensure-whole-of-status-is-visible win)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +twitter-buffer-p (buf)
|
||||
"Return non-nil if BUF is a `twittering-mode' buffer."
|
||||
(eq 'twittering-mode (buffer-local-value 'major-mode buf)))
|
||||
|
||||
|
||||
;;
|
||||
;; Commands
|
||||
|
||||
(defvar +twitter--old-wconf nil)
|
||||
;;;###autoload
|
||||
(defun =twitter (arg)
|
||||
"Opens a workspace dedicated to `twittering-mode'."
|
||||
(interactive "P")
|
||||
(condition-case _
|
||||
(progn
|
||||
(if (and (not arg) (featurep! :ui workspaces))
|
||||
(+workspace/new +twitter-workspace-name)
|
||||
(setq +twitter--old-wconf (current-window-configuration))
|
||||
(delete-other-windows)
|
||||
(switch-to-buffer (doom-fallback-buffer)))
|
||||
(call-interactively #'twit)
|
||||
(unless (get-buffer (car twittering-initial-timeline-spec-string))
|
||||
(error "Failed to open twitter"))
|
||||
(switch-to-buffer (car twittering-initial-timeline-spec-string))
|
||||
(dolist (name (cdr twittering-initial-timeline-spec-string))
|
||||
(split-window-horizontally)
|
||||
(switch-to-buffer name))
|
||||
(balance-windows)
|
||||
(call-interactively #'+twitter/rerender-all))
|
||||
('error (+twitter/quit-all))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +twitter/quit ()
|
||||
"Close the current `twitter-mode' buffer."
|
||||
(interactive)
|
||||
(when (eq major-mode 'twittering-mode)
|
||||
(twittering-kill-buffer)
|
||||
(cond ((one-window-p) (+twitter/quit-all))
|
||||
((featurep! :ui workspaces)
|
||||
(+workspace/close-window-or-workspace))
|
||||
((delete-window)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +twitter/quit-all ()
|
||||
"Close all open `twitter-mode' buffers and the associated workspace, if any."
|
||||
(interactive)
|
||||
(when (featurep! :ui workspaces)
|
||||
(+workspace/delete +twitter-workspace-name))
|
||||
(when +twitter--old-wconf
|
||||
(set-window-configuration +twitter--old-wconf)
|
||||
(setq +twitter--old-wconf nil))
|
||||
(dolist (buf (doom-buffers-in-mode 'twittering-mode (buffer-list) t))
|
||||
(twittering-kill-buffer buf)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +twitter/rerender-all ()
|
||||
"Rerender all `twittering-mode' buffers."
|
||||
(interactive)
|
||||
(dolist (buf (doom-buffers-in-mode 'twittering-mode (buffer-list) t))
|
||||
(with-current-buffer buf
|
||||
(twittering-rerender-timeline-all buf)
|
||||
(setq-local line-spacing 0.2)
|
||||
(goto-char (point-min)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +twitter/ace-link ()
|
||||
"Open a visible link, username or hashtag in a `twittering-mode' buffer."
|
||||
(interactive)
|
||||
(require 'avy)
|
||||
(let ((pt (avy-with +twitter/ace-link
|
||||
(avy--process
|
||||
(+twitter--collect-links)
|
||||
(avy--style-fn avy-style)))))
|
||||
(when (number-or-marker-p pt)
|
||||
(goto-char pt)
|
||||
(let ((uri (get-text-property (point) 'uri)))
|
||||
(if uri (browse-url uri))))))
|
||||
|
||||
(defun +twitter--collect-links ()
|
||||
(let ((end (window-end))
|
||||
points)
|
||||
(save-excursion
|
||||
(goto-char (window-start))
|
||||
(while (and (< (point) end)
|
||||
(ignore-errors (twittering-goto-next-thing) t))
|
||||
(push (point) points))
|
||||
(nreverse points))))
|
||||
79
.emacs.d/modules/app/twitter/config.el
Normal file
79
.emacs.d/modules/app/twitter/config.el
Normal file
@@ -0,0 +1,79 @@
|
||||
;;; app/twitter/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(use-package! twittering-mode
|
||||
:commands twit
|
||||
:config
|
||||
(setq twittering-private-info-file
|
||||
(expand-file-name "twittering-mode.gpg" doom-etc-dir)
|
||||
twittering-use-master-password t
|
||||
twittering-request-confirmation-on-posting t
|
||||
;; twittering-icon-mode t
|
||||
;; twittering-use-icon-storage t
|
||||
;; twittering-icon-storage-file (concat doom-cache-dir "twittering-mode-icons.gz")
|
||||
;; twittering-convert-fix-size 12
|
||||
twittering-timeline-header ""
|
||||
twittering-timeline-footer ""
|
||||
twittering-edit-skeleton 'inherit-any
|
||||
twittering-status-format "%FACE[font-lock-function-name-face]{ @%s} %FACE[italic]{%@} %FACE[error]{%FIELD-IF-NONZERO[❤ %d]{favorite_count}} %FACE[warning]{%FIELD-IF-NONZERO[↺ %d]{retweet_count}}
|
||||
%FOLD[ ]{%FILL{%t}%QT{
|
||||
%FOLD[ ]{%FACE[font-lock-function-name-face]{@%s}\t%FACE[shadow]{%@}
|
||||
%FOLD[ ]{%FILL{%t}}
|
||||
}}}
|
||||
|
||||
%FACE[twitter-divider]{ }
|
||||
"
|
||||
;; twittering-timeline-spec-alias '()
|
||||
twittering-initial-timeline-spec-string
|
||||
'(":home" ":mentions" ":direct_messages"))
|
||||
|
||||
(set-popup-rule! "^\\*twittering-edit" :size 15 :ttl nil :quit nil :select t)
|
||||
|
||||
(defface twitter-divider
|
||||
'((((background dark)) (:underline (:color "#141519")))
|
||||
(((background light)) (:underline (:color "#d3d3d3"))))
|
||||
"The vertical divider between tweets."
|
||||
:group 'twittering-mode)
|
||||
|
||||
(add-hook 'doom-real-buffer-functions #'+twitter-buffer-p)
|
||||
(when (featurep! :ui popup)
|
||||
(setq twittering-pop-to-buffer-function #'+twitter-display-buffer-fn))
|
||||
|
||||
(after! solaire-mode
|
||||
(add-hook 'twittering-mode-hook #'solaire-mode))
|
||||
|
||||
;; Custom header-line for twitter buffers
|
||||
(add-hook! 'twittering-mode-hook
|
||||
(defun +twitter-switch-mode-and-header-line-h ()
|
||||
(setq header-line-format mode-line-format
|
||||
mode-line-format nil)))
|
||||
|
||||
;; `epa--decode-coding-string' isn't defined in later versions of Emacs 27
|
||||
(unless (fboundp 'epa--decode-coding-string)
|
||||
(defalias 'epa--decode-coding-string #'decode-coding-string))
|
||||
|
||||
(define-key! twittering-mode-map
|
||||
"q" #'+twitter/quit
|
||||
"Q" #'+twitter/quit-all
|
||||
[remap twittering-kill-buffer] #'+twitter/quit
|
||||
[remap delete-window] #'+twitter/quit
|
||||
[remap +workspace/close-window-or-workspace] #'+twitter/quit)
|
||||
(when (featurep! :editor evil +everywhere)
|
||||
(define-key! twittering-mode-map
|
||||
[remap evil-window-delete] #'+twitter/quit
|
||||
"f" #'twittering-favorite
|
||||
"F" #'twittering-unfavorite
|
||||
"\C-f" #'twittering-follow
|
||||
"\C-F" #'twittering-unfollow
|
||||
"d" #'twittering-delete-status
|
||||
"r" #'twittering-retweet
|
||||
"R" #'twittering-toggle-or-retrieve-replied-statuses
|
||||
"o" #'twittering-update-status-interactive
|
||||
"O" #'+twitter/ace-link
|
||||
"/" #'twittering-search
|
||||
"J" #'twittering-goto-next-status
|
||||
"K" #'twittering-goto-previous-status
|
||||
"g" nil
|
||||
"gg" #'twittering-goto-first-status
|
||||
"G" #'twittering-goto-last-status
|
||||
"gj" #'twittering-goto-next-status-of-user
|
||||
"gk" #'twittering-goto-previous-status-of-user)))
|
||||
5
.emacs.d/modules/app/twitter/packages.el
Normal file
5
.emacs.d/modules/app/twitter/packages.el
Normal file
@@ -0,0 +1,5 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; app/twitter/packages.el
|
||||
|
||||
(package! twittering-mode)
|
||||
(package! avy)
|
||||
131
.emacs.d/modules/app/write/README.org
Normal file
131
.emacs.d/modules/app/write/README.org
Normal file
@@ -0,0 +1,131 @@
|
||||
#+TITLE: app/write
|
||||
#+DATE: October 10, 2019
|
||||
#+SINCE: v1.3
|
||||
#+STARTUP: inlineimages
|
||||
|
||||
* Table of Contents :TOC_3:noexport:
|
||||
- [[#description][Description]]
|
||||
- [[#module-flags][Module Flags]]
|
||||
- [[#plugins][Plugins]]
|
||||
- [[#prerequisites][Prerequisites]]
|
||||
- [[#language-tool][Language Tool]]
|
||||
- [[#wordnut][Wordnut]]
|
||||
- [[#features][Features]]
|
||||
- [[#m-x-write-mode][~M-x +write-mode~]]
|
||||
- [[#language-tool-langtool][Language Tool ~+langtool~]]
|
||||
- [[#commands][Commands]]
|
||||
- [[#wordnut-wordnut][Wordnut ~+wordnut~]]
|
||||
- [[#commands-1][Commands]]
|
||||
- [[#synosaurus][Synosaurus]]
|
||||
- [[#commands-2][Commands]]
|
||||
- [[#configuration][Configuration]]
|
||||
- [[#mixed-pitch-mode][mixed-pitch-mode]]
|
||||
- [[#appendix][Appendix]]
|
||||
- [[#minor-modes][Minor modes]]
|
||||
- [[#commands-3][Commands]]
|
||||
|
||||
* Description
|
||||
Adds word processing tools and the ~+write-mode~ minor mode, which converts
|
||||
Emacs into a more comfortable writing environment.
|
||||
|
||||
** Module Flags
|
||||
This module provides two module flags:
|
||||
|
||||
- ~+langtool~ Enables language tool integration.
|
||||
- ~+wordnut~ Enables wordnet integration.
|
||||
|
||||
** Plugins
|
||||
+ [[https://github.com/hpdeifel/synosaurus][synosaurus]]
|
||||
+ [[https://gitlab.com/jabranham/mixed-pitch][mixed-pitch]]
|
||||
+ [[https://github.com/joostkremers/visual-fill-column][visual-fill-column]]
|
||||
+ [[https://github.com/mhayashi1120/Emacs-langtool][langtool]]* (=+langtool=)
|
||||
+ [[https://github.com/gromnitsky/wordnut][wordnut]]* (=+wordnut=)
|
||||
|
||||
* Prerequisites
|
||||
** Language Tool
|
||||
Either download and deploy it from https://languagetool.org/ or install it
|
||||
through your OS package manager:
|
||||
|
||||
#+BEGIN_SRC sh
|
||||
# MacOS/Homebrew users:
|
||||
brew install languagetool
|
||||
|
||||
# Arch Linux users:
|
||||
sudo pacman -S languagetool
|
||||
#+END_SRC
|
||||
|
||||
This module tries to guess the location of languagetool-commandline.jar. If you
|
||||
get a warning that Doom =couldn't find languagetool-commandline.jar=, you will
|
||||
need to find langaugetool-commandline.jar and set ~langtool-language-tool-jar~
|
||||
to its path.
|
||||
|
||||
** Wordnut
|
||||
This requires =wordnet= to be installed, which should be available through your
|
||||
OS package manager:
|
||||
|
||||
#+BEGIN_SRC sh
|
||||
# MacOS/Homebrew users:
|
||||
brew install wordnet
|
||||
|
||||
# Arch Linux users:
|
||||
sudo pacaur -S wordnet # on the AUR
|
||||
#+END_SRC
|
||||
|
||||
* Features
|
||||
** ~M-x +write-mode~
|
||||
Write mode makes Emacs a more comfortable writing environment by:
|
||||
|
||||
- Centering the buffer (with ~visual-fill-column-mode~), ala distraction-free
|
||||
mode from other text editors.
|
||||
- Soft-wrapping long text lines with ~visual-line-mode~.
|
||||
- Enabling ~mixed-pitch-mode~, allowing fixed-width and variable-pitch fonts to
|
||||
co-exist in one buffer. For example, a monospace font for SRC blocks and Arial
|
||||
for everything else.
|
||||
- In org-mode:
|
||||
- Turns on ~org-indent-mode~
|
||||
- Turns on ~+org-pretty-mode~
|
||||
|
||||
** Language Tool ~+langtool~
|
||||
[[https://www.languagetool.org/][Language Tool]] is a polyglot proofreader service that checks for grammar and
|
||||
stylistic issues in your writing. This requires Java 1.8+.
|
||||
|
||||
#+begin_quote
|
||||
This requires Java 1.8+
|
||||
#+end_quote
|
||||
|
||||
*** Commands
|
||||
- ~langtool-check~
|
||||
- ~langtool-correct-buffer~
|
||||
|
||||
** Wordnut ~+wordnut~
|
||||
Wordnut provides a searchable dictionary frontend for Emacs. This requires
|
||||
~wordnet~, which should be available in your OS's package manager.
|
||||
|
||||
*** Commands
|
||||
- ~wordnut-search~
|
||||
- ~wordnut-lookup-curent-word~
|
||||
|
||||
** Synosaurus
|
||||
Synosaurus provides a service for looking up synonyms. It requires an internet
|
||||
connection.
|
||||
|
||||
*** Commands
|
||||
- ~synosaurus-lookup~
|
||||
- ~synosaurus-choose-and-replace~
|
||||
|
||||
* Configuration
|
||||
** mixed-pitch-mode
|
||||
To configure which faces are displayed with fixed-pitch fonts in
|
||||
~mixed-pitch-mode~, look into ~mixed-pitch-fixed-pitch-faces~.
|
||||
|
||||
* Appendix
|
||||
** Minor modes
|
||||
- ~+write-mode~
|
||||
- ~mixed-pitch-mode~
|
||||
** Commands
|
||||
- ~langtool-check~
|
||||
- ~langtool-correct-buffer~
|
||||
- ~synosaurus-choose-and-replace~
|
||||
- ~synosaurus-lookup~
|
||||
- ~wordnut-lookup-curent-word~
|
||||
- ~wordnut-search~
|
||||
43
.emacs.d/modules/app/write/autoload.el
Normal file
43
.emacs.d/modules/app/write/autoload.el
Normal file
@@ -0,0 +1,43 @@
|
||||
;;; app/write/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defvar +write-mode-map (make-sparse-keymap)
|
||||
"TODO")
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode +write-mode
|
||||
"Turns Emacs into a more comfortable writing environment and word processor."
|
||||
:init-value nil
|
||||
:keymap +write-mode-map
|
||||
(setq-local visual-fill-column-center-text t)
|
||||
(when +write-text-scale
|
||||
(text-scale-set (if +write-mode 2 0)))
|
||||
(when +write-line-spacing
|
||||
(setq-local line-spacing +write-line-spacing)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +write-init-org-mode-h ()
|
||||
"Initializes `org-mode' specific settings for `+write-mode'."
|
||||
(when (eq major-mode 'org-mode)
|
||||
(+org-pretty-mode (if +write-mode +1 -1))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +write-init-line-numbers-h ()
|
||||
(display-line-numbers-mode (if +write-mode +1 -1)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +write-init-mixed-pitch-h ()
|
||||
(mixed-pitch-mode (if +write-mode +1 -1)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +write-init-visual-fill-column-h ()
|
||||
(visual-fill-column-mode (if +write-mode +1 -1)))
|
||||
|
||||
;;;###autoload
|
||||
(add-hook! '+write-mode-hook
|
||||
#'(flyspell-mode
|
||||
visual-line-mode
|
||||
+write-init-mixed-pitch-h
|
||||
+write-init-visual-fill-column-h
|
||||
+write-init-line-numbers-h
|
||||
+write-init-org-mode-h))
|
||||
56
.emacs.d/modules/app/write/config.el
Normal file
56
.emacs.d/modules/app/write/config.el
Normal file
@@ -0,0 +1,56 @@
|
||||
;;; app/write/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +write-text-scale nil
|
||||
"What to scale the text up to in `+write-mode'. Uses `text-scale-set'.")
|
||||
|
||||
(defvar +write-line-spacing nil
|
||||
"What to set `line-spacing' in `+write-mode'.")
|
||||
|
||||
;;
|
||||
;; Packages
|
||||
|
||||
(use-package! langtool
|
||||
:when (featurep! +langtool)
|
||||
:commands (langtool-check
|
||||
langtool-check-done
|
||||
langtool-show-message-at-point
|
||||
langtool-correct-buffer)
|
||||
:init (setq langtool-default-language "en-US")
|
||||
:config
|
||||
(unless langtool-language-tool-jar
|
||||
(setq langtool-language-tool-jar
|
||||
(cond (IS-MAC
|
||||
(locate-file "libexec/languagetool-commandline.jar"
|
||||
(doom-files-in "/usr/local/Cellar/languagetool"
|
||||
:type 'dirs
|
||||
:depth 2)))
|
||||
(IS-LINUX
|
||||
"/usr/share/java/languagetool/languagetool-commandline.jar")))))
|
||||
|
||||
|
||||
;; `synosaurus'
|
||||
(setq synosaurus-choose-method 'default)
|
||||
|
||||
|
||||
;; `mixed-pitch'
|
||||
(after! mixed-pitch
|
||||
(setq mixed-pitch-fixed-pitch-faces
|
||||
(append mixed-pitch-fixed-pitch-faces
|
||||
'(org-todo-keyword-todo
|
||||
org-todo-keyword-habt
|
||||
org-todo-keyword-done
|
||||
org-todo-keyword-wait
|
||||
org-todo-keyword-kill
|
||||
org-todo-keyword-outd
|
||||
org-todo
|
||||
org-indent
|
||||
line-number
|
||||
line-number-current-line
|
||||
org-special-keyword
|
||||
org-date
|
||||
org-property-value
|
||||
org-special-keyword
|
||||
org-property-value
|
||||
org-ref-cite-face
|
||||
org-tag
|
||||
font-lock-comment-face))))
|
||||
7
.emacs.d/modules/app/write/doctor.el
Normal file
7
.emacs.d/modules/app/write/doctor.el
Normal file
@@ -0,0 +1,7 @@
|
||||
;; -*- lexical-binding: t; no-byte-compile: t; -*-
|
||||
;;; app/write/doctor.el
|
||||
|
||||
(when (featurep! +langtool)
|
||||
(require 'langtool)
|
||||
(unless (file-exists-p langtool-language-tool-jar)
|
||||
(warn! "Couldn't find languagetool-commandline.jar")))
|
||||
12
.emacs.d/modules/app/write/packages.el
Normal file
12
.emacs.d/modules/app/write/packages.el
Normal file
@@ -0,0 +1,12 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; app/write/packages.el
|
||||
|
||||
(package! synosaurus)
|
||||
(package! mixed-pitch)
|
||||
|
||||
(when (featurep! +langtool)
|
||||
(package! langtool))
|
||||
(when (featurep! +wordnut)
|
||||
(package! wordnut))
|
||||
|
||||
(package! visual-fill-column)
|
||||
Reference in New Issue
Block a user