this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

initial commit

+3485
+2
README.md
··· 1 + My Emacs configuration which is, right now, [spacemacs (develop)](https://github.com/syl20bnr/spacemacs/tree/develop). 2 + This prohect is used by my [nix-config](https://github.com/kaychaks/nix-config).
+690
spacemacs
··· 1 + ;; -*- mode: emacs-lisp -*- 2 + ;; This file is loaded by Spacemacs at startup. 3 + ;; It must be stored in your home directory. 4 + 5 + (defun dotspacemacs/layers () 6 + "Layer configuration: 7 + This function should only modify configuration layer settings." 8 + (setq-default 9 + ;; Base distribution to use. This is a layer contained in the directory 10 + ;; `+distribution'. For now available distributions are `spacemacs-base' 11 + ;; or `spacemacs'. (default 'spacemacs) dotspacemacs-distribution 'spacemacs 12 + ;; Lazy installation of layers (i.e. layers are installed only when a file 13 + ;; with a supported type is opened). Possible values are `all', `unused' 14 + ;; and `nil'. `unused' will lazy install only unused layers (i.e. layers 15 + ;; not listed in variable `dotspacemacs-configuration-layers'), `all' will 16 + ;; lazy install any layer that support lazy installation even the layers 17 + ;; listed in `dotspacemacs-configuration-layers'. `nil' disable the lazy 18 + ;; installation feature and you have to explicitly list a layer in the 19 + ;; variable `dotspacemacs-configuration-layers' to install it. 20 + ;; (default 'unused) dotspacemacs-enable-lazy-installation 'unused 21 + ;; If non-nil then Spacemacs will ask for confirmation before installing 22 + ;; a layer lazily. (default t) 23 + dotspacemacs-ask-for-lazy-installation 24 + t 25 + ;; If non-nil layers with lazy install support are lazy installed. 26 + ;; List of additional paths where to look for configuration layers. 27 + ;; Paths must have a trailing slash (i.e. `~/.mycontribs/') 28 + dotspacemacs-configuration-layer-path 29 + '("~/.local/share/spacemacs/private/") 30 + ;; List of configuration layers to load. 31 + dotspacemacs-configuration-layers 32 + '( 33 + osx 34 + javascript 35 + html 36 + helm 37 + syntax-checking 38 + (auto-completion (:variables 39 + auto-completion-enable-snippets-in-popup t 40 + auto-completion-enable-help-tooltip t)) 41 + (better-defaults :variables 42 + better-defaults-move-to-beginning-of-code-first t 43 + better-defaults-move-to-end-of-code-first nil) 44 + emacs-lisp 45 + git 46 + markdown 47 + treemacs 48 + (org :variables 49 + org-enable-github-support nil) 50 + (shell :variables 51 + shell-default-height 30 52 + shell-default-position 'bottom) 53 + (spell-checking :variables 54 + spell-checking-enable-by-default nil 55 + spell-checking-enable-auto-dictionary nil 56 + enable-flyspell-auto-completion nil) 57 + python 58 + yaml 59 + shell-scripts 60 + (haskell :variables 61 + haskell-completion-backend 'dante 62 + haskell-enable-ghc-mod-support nil 63 + haskell-enable-hindent t 64 + haskell-process-type 'ghci) 65 + pandoc 66 + (latex :variables 67 + latex-build-command "LaTeX") 68 + bibtex 69 + octave 70 + 71 + ;; all private layers 72 + custom-lean 73 + custom-super-save 74 + custom-nix 75 + custom-haskell 76 + custom-config-org 77 + custom-config-evil 78 + custom-direnv 79 + 80 + ) 81 + ;; List of additional packages that will be installed without being 82 + ;; wrapped in a layer. If you need some configuration for these 83 + ;; packages, then consider creating a layer. You can also put the 84 + ;; configuration in `dotspacemacs/user-config'. 85 + ;; To use a local version of a package, use the `:location' property: 86 + ;; '(your-package :location "~/path/to/your-package/") 87 + ;; Also include the dependencies as they will not be resolved automatically. 88 + dotspacemacs-additional-packages 89 + '( 90 + ;; direnv 91 + ) 92 + ;; A list of packages that cannot be updated. 93 + dotspacemacs-frozen-packages 94 + '() 95 + ;; A list of packages that will not be installed and loaded. 96 + dotspacemacs-excluded-packages 97 + '() 98 + ;; Defines the behaviour of Spacemacs when installing packages. 99 + ;; Possible values are `used-only', `used-but-keep-unused' and `all'. 100 + ;; `used-only' installs only explicitly used packages and deletes any unused 101 + ;; packages as well as their unused dependencies. `used-but-keep-unused' 102 + ;; installs only the used packages but won't delete unused ones. `all' 103 + ;; installs *all* packages supported by Spacemacs and never uninstalls them. 104 + ;; (default is `used-only') 105 + dotspacemacs-install-packages 106 + 'used-only)) 107 + 108 + (defun dotspacemacs/init () 109 + "Initialization: 110 + This function is called at the very beginning of Spacemacs startup, 111 + before layer configuration. 112 + It should only modify the values of Spacemacs settings." 113 + ;; This setq-default sexp is an exhaustive list of all the supported 114 + ;; spacemacs settings. 115 + (setq-default 116 + ;; If non-nil ELPA repositories are contacted via HTTPS whenever it's 117 + ;; possible. Set it to nil if you have no way to use HTTPS in your 118 + ;; environment, otherwise it is strongly recommended to let it set to t. 119 + ;; This variable has no effect if Emacs is launched with the parameter 120 + ;; `--insecure' which forces the value of this variable to nil. 121 + ;; (default t) dotspacemacs-elpa-https nil 122 + ;; Maximum allowed time in seconds to contact an ELPA repository. 123 + ;; (default 5) dotspacemacs-elpa-timeout 5 124 + ;; Set `gc-cons-threshold' and `gc-cons-percentage' when startup finishes. 125 + ;; This is an advanced option and should not be changed unless you suspect 126 + ;; performance issues due to garbage collection operations. 127 + ;; (default '(100000000 0.1)) 128 + dotspacemacs-gc-cons 129 + '(100000000 0.1) 130 + ;; If non-nil then Spacelpa repository is the primary source to install 131 + ;; a locked version of packages. If nil then Spacemacs will install the 132 + ;; latest version of packages from MELPA. (default nil) 133 + dotspacemacs-use-spacelpa 134 + nil 135 + ;; If non-nil then verify the signature for downloaded Spacelpa archives. 136 + ;; (default nil) 137 + dotspacemacs-verify-spacelpa-archives 138 + nil 139 + ;; If non-nil then spacemacs will check for updates at startup 140 + ;; when the current branch is not `develop'. Note that checking for 141 + ;; new versions works via git commands, thus it calls GitHub services 142 + ;; whenever you start Emacs. (default nil) 143 + dotspacemacs-check-for-update 144 + nil 145 + ;; If non-nil, a form that evaluates to a package directory. For example, to 146 + ;; use different package directories for different Emacs versions, set this 147 + ;; to `emacs-version'. (default 'emacs-version) 148 + dotspacemacs-elpa-subdirectory 149 + 'emacs-version 150 + ;; One of `vim', `emacs' or `hybrid'. 151 + ;; `hybrid' is like `vim' except that `insert state' is replaced by the 152 + ;; `hybrid state' with `emacs' key bindings. The value can also be a list 153 + ;; with `:variables' keyword (similar to layers). Check the editing styles 154 + ;; section of the documentation for details on available variables. 155 + ;; (default 'vim) 156 + dotspacemacs-editing-style 157 + 'vim 158 + ;; If non-nil output loading progress in `*Messages*' buffer. (default nil) 159 + dotspacemacs-verbose-loading 160 + t 161 + ;; Specify the startup banner. Default value is `official', it displays 162 + ;; the official spacemacs logo. An integer value is the index of text 163 + ;; banner, `random' chooses a random text banner in `core/banners' 164 + ;; directory. A string value must be a path to an image format supported 165 + ;; by your Emacs build. 166 + ;; If the value is nil then no banner is displayed. (default 'official) 167 + dotspacemacs-startup-banner 168 + nil 169 + ;; List of items to show in startup buffer or an association list of 170 + ;; the form `(list-type . list-size)`. If nil then it is disabled. 171 + ;; Possible values for list-type are: 172 + ;; `recents' `bookmarks' `projects' `agenda' `todos'. 173 + ;; List sizes may be nil, in which case 174 + ;; `spacemacs-buffer-startup-lists-length' takes effect. 175 + dotspacemacs-startup-lists 176 + nil 177 + ;; True if the home buffer should respond to resize events. (default t) 178 + dotspacemacs-startup-buffer-responsive 179 + t 180 + ;; Default major mode of the scratch buffer (default `text-mode') 181 + dotspacemacs-scratch-mode 182 + 'org-mode 183 + ;; Initial message in the scratch buffer, such as "Welcome to Spacemacs!" 184 + ;; (default nil) 185 + dotspacemacs-initial-scratch-message 186 + nil 187 + ;; List of themes, the first of the list is loaded when spacemacs starts. 188 + ;; Press `SPC T n' to cycle to the next theme in the list (works great 189 + ;; with 2 themes variants, one dark and one light) 190 + dotspacemacs-themes 191 + '(spacemacs-dark 192 + sanityinc-solarized-dark 193 + spacemacs-light 194 + material 195 + ) 196 + ;; Set the theme for the Spaceline. Supported themes are `spacemacs', 197 + ;; `all-the-icons', `custom', `vim-powerline' and `vanilla'. The first three 198 + ;; are spaceline themes. `vanilla' is default Emacs mode-line. `custom' is a 199 + ;; user defined themes, refer to the DOCUMENTATION.org for more info on how 200 + ;; to create your own spaceline theme. Value can be a symbol or list with\ 201 + ;; additional properties. 202 + ;; (default '(spacemacs :separator wave :separator-scale 1.5)) 203 + dotspacemacs-mode-line-theme 204 + '(vim-powerline :separator wave 205 + :separator-scale 1.5) 206 + ;; If non-nil the cursor color matches the state color in GUI Emacs. 207 + ;; (default t) 208 + dotspacemacs-colorize-cursor-according-to-state 209 + t 210 + ;; Default font, or prioritized list of fonts. `powerline-scale' allows to 211 + ;; quickly tweak the mode-line size to make separators look not too crappy. 212 + dotspacemacs-default-font 213 + '("Fira Code" :size 16 214 + :weight normal 215 + :width normal 216 + :powerline-scale 1.1) 217 + ;; The leader key (default "SPC") 218 + dotspacemacs-leader-key 219 + "SPC" 220 + ;; The key used for Emacs commands `M-x' (after pressing on the leader key). 221 + ;; (default "SPC") 222 + dotspacemacs-emacs-command-key 223 + "SPC" 224 + ;; The key used for Vim Ex commands (default ":") 225 + dotspacemacs-ex-command-key 226 + ":" 227 + ;; The leader key accessible in `emacs state' and `insert state' 228 + ;; (default "M-m") 229 + dotspacemacs-emacs-leader-key 230 + "M-m" 231 + ;; Major mode leader key is a shortcut key which is the equivalent of 232 + ;; pressing `<leader> m`. Set it to `nil` to disable it. (default ",") 233 + dotspacemacs-major-mode-leader-key 234 + "," 235 + ;; Major mode leader key accessible in `emacs state' and `insert state'. 236 + ;; (default "C-M-m") 237 + dotspacemacs-major-mode-emacs-leader-key 238 + "C-M-m" 239 + ;; These variables control whether separate commands are bound in the GUI to 240 + ;; the key pairs `C-i', `TAB' and `C-m', `RET'. 241 + ;; Setting it to a non-nil value, allows for separate commands under `C-i' 242 + ;; and TAB or `C-m' and `RET'. 243 + ;; In the terminal, these pairs are generally indistinguishable, so this only 244 + ;; works in the GUI. (default nil) 245 + dotspacemacs-distinguish-gui-tab 246 + nil 247 + ;; If non-nil `Y' is remapped to `y$' in Evil states. (default nil) 248 + dotspacemacs-remap-Y-to-y$ 249 + nil 250 + ;; If non-nil, the shift mappings `<' and `>' retain visual state if used 251 + ;; there. (default t) 252 + dotspacemacs-retain-visual-state-on-shift 253 + t 254 + ;; If non-nil, `J' and `K' move lines up and down when in visual mode. 255 + ;; (default nil) 256 + dotspacemacs-visual-line-move-text 257 + t 258 + ;; If non-nil, inverse the meaning of `g' in `:substitute' Evil ex-command. 259 + ;; (default nil) 260 + dotspacemacs-ex-substitute-global 261 + nil 262 + ;; Name of the default layout (default "Default") 263 + dotspacemacs-default-layout-name 264 + "Default" 265 + ;; If non-nil the default layout name is displayed in the mode-line. 266 + ;; (default nil) 267 + dotspacemacs-display-default-layout 268 + nil 269 + ;; If non-nil then the last auto saved layouts are resumed automatically upon 270 + ;; start. (default nil) 271 + dotspacemacs-auto-resume-layouts 272 + nil 273 + ;; If non-nil, auto-generate layout name when creating new layouts. Only has 274 + ;; effect when using the "jump to layout by number" commands. (default nil) 275 + dotspacemacs-auto-generate-layout-names 276 + nil 277 + ;; Size (in MB) above which spacemacs will prompt to open the large file 278 + ;; literally to avoid performance issues. Opening a file literally means that 279 + ;; no major mode or minor modes are active. (default is 1) 280 + dotspacemacs-large-file-size 281 + 1 282 + ;; Location where to auto-save files. Possible values are `original' to 283 + ;; auto-save the file in-place, `cache' to auto-save the file to another 284 + ;; file stored in the cache directory and `nil' to disable auto-saving. 285 + ;; (default 'cache) 286 + dotspacemacs-auto-save-file-location 287 + nil 288 + ;; Maximum number of rollback slots to keep in the cache. (default 5) 289 + dotspacemacs-max-rollback-slots 290 + 5 291 + ;; If non-nil, `helm' will try to minimize the space it uses. (default nil) 292 + dotspacemacs-helm-resize 293 + nil 294 + ;; if non-nil, the helm header is hidden when there is only one source. 295 + ;; (default nil) 296 + dotspacemacs-helm-no-header 297 + t 298 + ;; define the position to display `helm', options are `bottom', `top', 299 + ;; `left', or `right'. (default 'bottom) 300 + dotspacemacs-helm-position 301 + 'bottom 302 + ;; Controls fuzzy matching in helm. If set to `always', force fuzzy matching 303 + ;; in all non-asynchronous sources. If set to `source', preserve individual 304 + ;; source settings. Else, disable fuzzy matching in all sources. 305 + ;; (default 'always) 306 + dotspacemacs-helm-use-fuzzy 307 + 'always 308 + ;; If non-nil, the paste transient-state is enabled. While enabled, pressing 309 + ;; `p' several times cycles through the elements in the `kill-ring'. 310 + ;; (default nil) 311 + dotspacemacs-enable-paste-transient-state 312 + nil 313 + ;; Which-key delay in seconds. The which-key buffer is the popup listing 314 + ;; the commands bound to the current keystroke sequence. (default 0.4) 315 + dotspacemacs-which-key-delay 316 + 0.4 317 + ;; Which-key frame position. Possible values are `right', `bottom' and 318 + ;; `right-then-bottom'. right-then-bottom tries to display the frame to the 319 + ;; right; if there is insufficient space it displays it at the bottom. 320 + ;; (default 'bottom) 321 + dotspacemacs-which-key-position 322 + 'bottom 323 + ;; Control where `switch-to-buffer' displays the buffer. If nil, 324 + ;; `switch-to-buffer' displays the buffer in the current window even if 325 + ;; another same-purpose window is available. If non-nil, `switch-to-buffer' 326 + ;; displays the buffer in a same-purpose window even if the buffer can be 327 + ;; displayed in the current window. (default nil) 328 + dotspacemacs-switch-to-buffer-prefers-purpose 329 + nil 330 + ;; If non-nil a progress bar is displayed when spacemacs is loading. This 331 + ;; may increase the boot time on some systems and emacs builds, set it to 332 + ;; nil to boost the loading time. (default t) 333 + dotspacemacs-loading-progress-bar 334 + nil 335 + ;; If non-nil the frame is fullscreen when Emacs starts up. (default nil) 336 + ;; (Emacs 24.4+ only) 337 + dotspacemacs-fullscreen-at-startup 338 + nil 339 + ;; If non-nil `spacemacs/toggle-fullscreen' will not use native fullscreen. 340 + ;; Use to disable fullscreen animations in OSX. (default nil) 341 + dotspacemacs-fullscreen-use-non-native 342 + nil 343 + ;; If non-nil the frame is maximized when Emacs starts up. 344 + ;; Takes effect only if `dotspacemacs-fullscreen-at-startup' is nil. 345 + ;; (default nil) (Emacs 24.4+ only) 346 + dotspacemacs-maximized-at-startup 347 + t 348 + ;; A value from the range (0..100), in increasing opacity, which describes 349 + ;; the transparency level of a frame when it's active or selected. 350 + ;; Transparency can be toggled through `toggle-transparency'. (default 90) 351 + dotspacemacs-active-transparency 352 + 90 353 + ;; A value from the range (0..100), in increasing opacity, which describes 354 + ;; the transparency level of a frame when it's inactive or deselected. 355 + ;; Transparency can be toggled through `toggle-transparency'. (default 90) 356 + dotspacemacs-inactive-transparency 357 + 90 358 + ;; If non-nil show the titles of transient states. (default t) 359 + dotspacemacs-show-transient-state-title 360 + t 361 + ;; If non-nil show the color guide hint for transient state keys. (default t) 362 + dotspacemacs-show-transient-state-color-guide 363 + t 364 + ;; If non-nil unicode symbols are displayed in the mode line. (default t) 365 + dotspacemacs-mode-line-unicode-symbols 366 + t 367 + ;; If non-nil smooth scrolling (native-scrolling) is enabled. Smooth 368 + ;; scrolling overrides the default behavior of Emacs which recenters point 369 + ;; when it reaches the top or bottom of the screen. (default t) 370 + dotspacemacs-smooth-scrolling 371 + t 372 + ;; Control line numbers activation. 373 + ;; If set to `t' or `relative' line numbers are turned on in all `prog-mode' and 374 + ;; `text-mode' derivatives. If set to `relative', line numbers are relative. 375 + ;; This variable can also be set to a property list for finer control: 376 + ;; '(:relative nil 377 + ;; :disabled-for-modes dired-mode 378 + ;; doc-view-mode 379 + ;; markdown-mode 380 + ;; org-mode 381 + ;; pdf-view-mode 382 + ;; text-mode 383 + ;; :size-limit-kb 1000) 384 + ;; (default nil) 385 + dotspacemacs-line-numbers 386 + 't 387 + ;; Code folding method. Possible values are `evil' and `origami'. 388 + ;; (default 'evil) 389 + dotspacemacs-folding-method 390 + 'evil 391 + ;; If non-nil `smartparens-strict-mode' will be enabled in programming modes. 392 + ;; (default nil) 393 + dotspacemacs-smartparens-strict-mode 394 + nil 395 + ;; If non-nil pressing the closing parenthesis `)' key in insert mode passes 396 + ;; over any automatically added closing parenthesis, bracket, quote, etc… 397 + ;; This can be temporary disabled by pressing `C-q' before `)'. (default nil) 398 + dotspacemacs-smart-closing-parenthesis 399 + nil 400 + ;; Select a scope to highlight delimiters. Possible values are `any', 401 + ;; `current', `all' or `nil'. Default is `all' (highlight any scope and 402 + ;; emphasis the current one). (default 'all) 403 + dotspacemacs-highlight-delimiters 404 + 'all 405 + ;; If non-nil, start an Emacs server if one is not already running. 406 + dotspacemacs-enable-server 407 + nil 408 + ;; If non-nil, advise quit functions to keep server open when quitting. 409 + ;; (default nil) 410 + dotspacemacs-persistent-server 411 + nil 412 + ;; List of search tool executable names. Spacemacs uses the first installed 413 + ;; tool of the list. Supported tools are `rg', `ag', `pt', `ack' and `grep'. 414 + ;; (default '("rg" "ag" "pt" "ack" "grep")) 415 + dotspacemacs-search-tools 416 + '("rg" "ag" "pt" "ack" "grep") 417 + ;; Format specification for setting the frame title. 418 + ;; %a - the `abbreviated-file-name', or `buffer-name' 419 + ;; %t - `projectile-project-name' 420 + ;; %I - `invocation-name' 421 + ;; %S - `system-name' 422 + ;; %U - contents of $USER 423 + ;; %b - buffer name 424 + ;; %f - visited file name 425 + ;; %F - frame name 426 + ;; %s - process status 427 + ;; %p - percent of buffer above top of window, or Top, Bot or All 428 + ;; %P - percent of buffer above bottom of window, perhaps plus Top, or Bot or All 429 + ;; %m - mode name 430 + ;; %n - Narrow if appropriate 431 + ;; %z - mnemonics of buffer, terminal, and keyboard coding systems 432 + ;; %Z - like %z, but including the end-of-line format 433 + ;; (default "%I@%S") 434 + dotspacemacs-frame-title-format 435 + "%I@%S" 436 + ;; Format specification for setting the icon title format 437 + ;; (default nil - same as frame-title-format) 438 + dotspacemacs-icon-title-format 439 + nil 440 + ;; Delete whitespace while saving buffer. Possible values are `all' 441 + ;; to aggressively delete empty line and long sequences of whitespace, 442 + ;; `trailing' to delete only the whitespace at end of lines, `changed' to 443 + ;; delete only whitespace for changed lines or `nil' to disable cleanup. 444 + ;; (default nil) 445 + dotspacemacs-whitespace-cleanup 446 + nil 447 + ;; Either nil or a number of seconds. If non-nil zone out after the specified 448 + ;; number of seconds. (default nil) 449 + dotspacemacs-zone-out-when-idle 450 + nil 451 + ;; Run `spacemacs/prettify-org-buffer' when 452 + ;; visiting README.org files of Spacemacs. 453 + ;; (default nil) 454 + dotspacemacs-pretty-docs 455 + nil)) 456 + 457 + (defun dotspacemacs/user-init () 458 + "Initialization for user code: 459 + This function is called immediately after `dotspacemacs/init', before layer 460 + configuration. 461 + It is mostly for variables that should be set before packages are loaded. 462 + If you are unsure, try setting them in `dotspacemacs/user-config' first." 463 + ;; (load "/Users/kaushik/Developer/src/personal/git-wip/emacs/git-wip.el") 464 + (setq exec-path-from-shell-arguments '("-c")) 465 + ) 466 + 467 + (defun dotspacemacs/user-config () 468 + "Configuration for user code: 469 + This function is called at the very end of Spacemacs startup, after layer 470 + configuration. 471 + Put your configuration code here, except for variables that should be set 472 + before packages are loaded." 473 + (setq ispell-program-name "/Users/kaushik/.nix-profile/bin/aspell") 474 + 475 + ;; (when (configuration-layer/package-usedp 'haskell) 476 + ;; (add-hook 'haskell-interactive-mode-hook 477 + ;; (lambda () 478 + ;; (setq-local evil-move-cursor-back nil))) 479 + ;; (add-hook 'doc-view-mode-hook 'auto-revert-mode) 480 + ;; (add-hook 'dante-mode-hook 481 + ;; '(lambda () 482 + ;; (flycheck-add-next-checker 'haskell-dante 483 + ;; '(warning . haskell-hlint))))) 484 + 485 + ;; (spacemacs/set-leader-keys-for-major-mode 486 + ;; 'haskell-mode "M-." 'xref-find-definitions) 487 + 488 + ;; (require 'beeminder) 489 + 490 + ;; (direnv-mode) 491 + (global-company-mode) 492 + (global-set-key (kbd "S-SPC") 493 + #'company-complete) 494 + 495 + ;; (setq org-ref-pdf-directory '("/Users/kaushik/Documents/Papers Virtual Library/All Papers") 496 + ;; org-ref-default-bibliography 497 + ;; '("/Users/kaushik/Documents/Papers Virtual Library/All Papers/Ω Export/All Papers.bib") 498 + ;; org-ref-bibliography-notes 499 + ;; (concat org-directory "biblio-notes.org")) 500 + 501 + ;; Fira code 502 + ;; This works when using emacs --daemon + emacsclient 503 + (add-hook 'after-make-frame-functions 504 + (lambda (frame) 505 + (set-fontset-font t 506 + '(#Xe100 . #Xe16f) 507 + "Fira Code Symbol"))) 508 + ;; This works when using emacs without server/client 509 + (set-fontset-font t 510 + '(#Xe100 . #Xe16f) 511 + "Fira Code Symbol") 512 + ;; I haven't found one statement that makes both of the above situations work, so I use both for now 513 + (defconst fira-code-font-lock-keywords-alist (mapcar (lambda (regex-char-pair) 514 + `(,(car regex-char-pair) 515 + (0 516 + (prog1 () 517 + (compose-region (match-beginning 1) 518 + (match-end 1) 519 + ;; The first argument to concat is a string containing a literal tab 520 + 521 + ,(concat " " 522 + (list (decode-char 'ucs 523 + (cadr regex-char-pair))))))))) 524 + '(("\\(www\\)" #Xe100) 525 + ("[^/]\\(\\*\\*\\)[^/]" #Xe101) 526 + ("\\(\\*\\*\\*\\)" #Xe102) 527 + ("\\(\\*\\*/\\)" #Xe103) 528 + ("\\(\\*>\\)" #Xe104) 529 + ("[^*]\\(\\*/\\)" #Xe105) 530 + ("\\(\\\\\\\\\\)" #Xe106) 531 + ("\\(\\\\\\\\\\\\\\)" #Xe107) 532 + ("\\({-\\)" #Xe108) 533 + ;; ("\\(\\[\\]\\)" #Xe109) This is the [] ligature and I don't like 534 + ("\\(::\\)" #Xe10a) 535 + ("\\(:::\\)" #Xe10b) 536 + ("[^=]\\(:=\\)" #Xe10c) 537 + ("\\(!!\\)" #Xe10d) 538 + ("\\(!=\\)" #Xe10e) 539 + ("\\(!==\\)" #Xe10f) 540 + ("\\(-}\\)" #Xe110) 541 + ("\\(--\\)" #Xe111) 542 + ("\\(---\\)" #Xe112) 543 + ("\\(-->\\)" #Xe113) 544 + ("[^-]\\(->\\)" #Xe114) 545 + ("\\(->>\\)" #Xe115) 546 + ("\\(-<\\)" #Xe116) 547 + ("\\(-<<\\)" #Xe117) 548 + ("\\(-~\\)" #Xe118) 549 + ("\\(#{\\)" #Xe119) 550 + ("\\(#\\[\\)" #Xe11a) 551 + ("\\(##\\)" #Xe11b) 552 + ("\\(###\\)" #Xe11c) 553 + ("\\(####\\)" #Xe11d) 554 + ("\\(#(\\)" #Xe11e) 555 + ("\\(#\\?\\)" #Xe11f) 556 + ("\\(#_\\)" #Xe120) 557 + ("\\(#_(\\)" #Xe121) 558 + ("\\(\\.-\\)" #Xe122) 559 + ("\\(\\.=\\)" #Xe123) 560 + ("\\(\\.\\.\\)" #Xe124) 561 + ("\\(\\.\\.<\\)" #Xe125) 562 + ("\\(\\.\\.\\.\\)" #Xe126) 563 + ("\\(\\?=\\)" #Xe127) 564 + ("\\(\\?\\?\\)" #Xe128) 565 + ("\\(;;\\)" #Xe129) 566 + ("\\(/\\*\\)" #Xe12a) 567 + ("\\(/\\*\\*\\)" #Xe12b) 568 + ("\\(/=\\)" #Xe12c) 569 + ("\\(/==\\)" #Xe12d) 570 + ("\\(/>\\)" #Xe12e) 571 + ("\\(//\\)" #Xe12f) 572 + ("\\(///\\)" #Xe130) 573 + ("\\(&&\\)" #Xe131) 574 + ("\\(||\\)" #Xe132) 575 + ("\\(||=\\)" #Xe133) 576 + ;("[^|]\\(|=\\)" #Xe134) 577 + ("\\(|>\\)" #Xe135) 578 + ("\\(\\^=\\)" #Xe136) 579 + ("\\(\\$>\\)" #Xe137) 580 + ("\\(\\+\\+\\)" #Xe138) 581 + ("\\(\\+\\+\\+\\)" #Xe139) 582 + ("\\(\\+>\\)" #Xe13a) 583 + ("\\(=:=\\)" #Xe13b) 584 + ;("[^!/]\\(==\\)[^>]" #Xe13c) 585 + ("\\(===\\)" #Xe13d) 586 + ("\\(==>\\)" #Xe13e) 587 + ;("[^=]\\(=>\\)" #Xe13f) 588 + ("\\(=>>\\)" #Xe140) 589 + ("\\(<=\\)" #Xe141) 590 + ("\\(=<<\\)" #Xe142) 591 + ("\\(=/=\\)" #Xe143) 592 + ("\\(>-\\)" #Xe144) 593 + ("\\(>=\\)" #Xe145) 594 + ("\\(>=>\\)" #Xe146) 595 + ("[^-=]\\(>>\\)" #Xe147) 596 + ("\\(>>-\\)" #Xe148) 597 + ("\\(>>=\\)" #Xe149) 598 + ("\\(>>>\\)" #Xe14a) 599 + ("\\(<\\*\\)" #Xe14b) 600 + ("\\(<\\*>\\)" #Xe14c) 601 + ("\\(<|\\)" #Xe14d) 602 + ("\\(<|>\\)" #Xe14e) 603 + ("\\(<\\$\\)" #Xe14f) 604 + ("\\(<\\$>\\)" #Xe150) 605 + ("\\(<!--\\)" #Xe151) 606 + ("\\(<-\\)" #Xe152) 607 + ("\\(<--\\)" #Xe153) 608 + ("\\(<->\\)" #Xe154) 609 + ("\\(<\\+\\)" #Xe155) 610 + ("\\(<\\+>\\)" #Xe156) 611 + ("\\(<=\\)" #Xe157) 612 + ("\\(<==\\)" #Xe158) 613 + ("\\(<=>\\)" #Xe159) 614 + ("\\(<=<\\)" #Xe15a) 615 + ("\\(<>\\)" #Xe15b) 616 + ("[^-=]\\(<<\\)" #Xe15c) 617 + ("\\(<<-\\)" #Xe15d) 618 + ("\\(<<=\\)" #Xe15e) 619 + ("\\(<<<\\)" #Xe15f) 620 + ("\\(<~\\)" #Xe160) 621 + ("\\(<~~\\)" #Xe161) 622 + ("\\(</\\)" #Xe162) 623 + ("\\(</>\\)" #Xe163) 624 + ("\\(~@\\)" #Xe164) 625 + ("\\(~-\\)" #Xe165) 626 + ("\\(~=\\)" #Xe166) 627 + ("\\(~>\\)" #Xe167) 628 + ("[^<]\\(~~\\)" #Xe168) 629 + ("\\(~~>\\)" #Xe169) 630 + ("\\(%%\\)" #Xe16a) 631 + ;; ("\\(x\\)" #Xe16b) This ended up being hard to do properly so i'm leaving it out. 632 + ("[^:=]\\(:\\)[^:=]" #Xe16c) 633 + ("[^\\+<>]\\(\\+\\)[^\\+<>]" #Xe16d) 634 + ("[^\\*/<>]\\(\\*\\)[^\\*/<>]" #Xe16f)))) 635 + (defun add-fira-code-symbol-keywords () 636 + (font-lock-add-keywords nil fira-code-font-lock-keywords-alist)) 637 + (add-hook 'prog-mode-hook #'add-fira-code-symbol-keywords) 638 + 639 + ;; (defun export-yearly-agenda-as-ics () 640 + ;; (interactive) 641 + ;; (progn (org-agenda-list nil nil 'year) (org-agenda-write "/Users/kaushik/Dropbox/agenda.ics"))) 642 + ;; (autoload 'run-prolog "prolog" "Start a Prolog sub-process." t) 643 + ;; (autoload 'prolog-mode "prolog" "Major mode for editing Prolog programs." t) 644 + ;; (setq prolog-system 'swi) 645 + ;; (setq auto-mode-alist (append '(("\\.pl$" . prolog-mode) 646 + ;; ("\\.m$" . mercury-mode)) 647 + ;; auto-mode-alist)) 648 + 649 + ) 650 + 651 + 652 + 653 + ;; Do not write anything past this comment. This is where Emacs will 654 + ;; auto-generate custom variable definitions. 655 + (defun dotspacemacs/emacs-custom-settings () 656 + "Emacs custom settings. 657 + This is an auto-generated function, do not modify its content directly, use 658 + Emacs customize menu instead. 659 + This function is called at the very end of Spacemacs initialization." 660 + (custom-set-variables 661 + ;; custom-set-variables was added by Custom. 662 + ;; If you edit it by hand, you could mess it up, so be careful. 663 + ;; Your init file should contain only one such instance. 664 + ;; If there is more than one, they won't work right. 665 + '(dante-load-flags 666 + (quote 667 + ("+c" "-Wall" "-ferror-spans" "-fdefer-typed-holes" "-fdefer-type-errors" "-fno-diagnostics-show-caret"))) 668 + '(dante-methods 669 + (quote 670 + (new-build new-impure-nix new-nix nix impure-nix nix-ghci stack mafia bare-cabal bare-ghci styx))) 671 + '(dante-tap-type-time 2) 672 + '(evil-want-Y-yank-to-eol nil) 673 + '(haskell-compile-cabal-build-alt-command 674 + "cabal new-clean -s && cabal new-build --ghc-option=-ferror-spans") 675 + '(haskell-compile-cabal-build-command "cabal new-build --ghc-option=-ferror-spans") 676 + '(haskell-hasktags-arguments (quote ("-R"))) 677 + '(haskell-hasktags-path "fast-tags") 678 + '(haskell-hoogle-command "nil") 679 + '(haskell-process-suggest-hoogle-imports nil) 680 + '(haskell-stylish-on-save t) 681 + '(package-selected-packages 682 + (quote 683 + (direnv reveal-in-osx-finder osx-trash osx-dictionary osx-clipboard launchctl treemacs-projectile treemacs-evil treemacs org-download org-brain nix-mode hlint-refactor eyebrowse evil-visual-mark-mode evil-nerd-commenter evil-magit eval-sexp-fu editorconfig doom-modeline eldoc-eval define-word dante cython-mode aggressive-indent ace-link anaconda-mode ivy smartparens goto-chg company window-purpose imenu-list helm helm-core flycheck avy projectile magit f simple-httpd powerline visual-fill-column yasnippet-snippets yapfify yaml-mode xterm-color ws-butler writeroom-mode winum which-key web-mode web-beautify volatile-highlights vi-tilde-fringe uuidgen use-package unfill toc-org tagedit symon super-save string-inflection spaceline-all-the-icons smeargle slim-mode shrink-path shell-pop scss-mode sass-mode restart-emacs rainbow-delimiters pyvenv pytest pyenv-mode py-isort pug-mode prettier-js popwin pippel pipenv pip-requirements pfuture persp-mode pcre2el password-generator paradox pandoc-mode ox-pandoc overseer orgit org-projectile org-present org-pomodoro org-mime org-bullets open-junk-file nameless mwim multi-term move-text mmm-mode material-theme markdown-toc magit-svn magit-gitflow macrostep lorem-ipsum livid-mode live-py-mode link-hint lcr json-navigator json-mode js2-refactor js-doc insert-shebang indent-guide importmagic impatient-mode hungry-delete hl-todo hindent highlight-parentheses highlight-numbers highlight-indentation highlight helm-xref helm-themes helm-swoop helm-pydoc helm-purpose helm-projectile helm-org-rifle helm-mode-manager helm-make helm-lean helm-hoogle helm-gitignore helm-git-grep helm-flx helm-descbinds helm-css-scss helm-company helm-c-yasnippet helm-ag haskell-snippets haskell-mode google-translate golden-ratio gnuplot gitignore-templates gitconfig-mode gitattributes-mode git-timemachine git-messenger git-link git-commit gh-md fuzzy font-lock+ flyspell-correct-helm flycheck-bashate flx-ido fish-mode fill-column-indicator fancy-battery expand-region evil-visualstar evil-unimpaired evil-tutor evil-surround evil-org evil-numbers evil-matchit evil-lisp-state evil-lion evil-indent-plus evil-iedit-state evil-goggles evil-exchange evil-escape evil-ediff evil-cleverparens evil-args evil-anzu eshell-z eshell-prompt-extras esh-help emmet-mode elisp-slime-nav dumb-jump dotenv-mode diminish counsel-projectile company-web company-tern company-statistics company-shell company-lean company-cabal company-auctex company-anaconda column-enforce-mode color-theme-sanityinc-solarized cmm-mode clean-aindent-mode centered-cursor-mode auto-yasnippet auto-highlight-symbol auto-dictionary auto-compile ace-window ace-jump-helm-line ac-ispell)))) 684 + (custom-set-faces 685 + ;; custom-set-faces was added by Custom. 686 + ;; If you edit it by hand, you could mess it up, so be careful. 687 + ;; Your init file should contain only one such instance. 688 + ;; If there is more than one, they won't work right. 689 + ) 690 + )
+21
spacemacs-private/README.md
··· 1 + # Private directory 2 + 3 + The content of this directory is ignored by Git. This is the default place 4 + where to store your private configuration layers. 5 + 6 + To create a new configuration layer: 7 + 8 + SPC SPC configuration-layer/create-layer RET 9 + 10 + Then enter the name of your configuration in the prompt. 11 + 12 + A directory named after the created configuration layer will be created here 13 + along with template files within it (packages.el and extensions.el, more info 14 + on the meaning of those files can be found in the [documentation][conf_layers]). 15 + 16 + Each created file has further guidance written in them. 17 + 18 + Once the configuration is done, restart Emacs to load, install and configure 19 + your layer. 20 + 21 + [conf_layers]: https://github.com/syl20bnr/spacemacs/blob/master/doc/DOCUMENTATION.org#extensions-and-packages
+41
spacemacs-private/custom-config-evil/packages.el
··· 1 + ;;; packages.el --- custom-config-evil layer packages file for Spacemacs. 2 + ;; 3 + ;; Copyright (c) 2012-2018 Sylvain Benner & Contributors 4 + ;; 5 + ;; Author: Kaushik Chakraborty <kaushik@AMB00472.local> 6 + ;; URL: https://github.com/syl20bnr/spacemacs 7 + ;; 8 + ;; This file is not part of GNU Emacs. 9 + ;; 10 + ;;; License: GPLv3 11 + 12 + ;;; Commentary: 13 + 14 + ;; See the Spacemacs documentation and FAQs for instructions on how to implement 15 + ;; a new layer: 16 + ;; 17 + ;; SPC h SPC layers RET 18 + ;; 19 + ;; 20 + ;; Briefly, each package to be installed or configured by this layer should be 21 + ;; added to `custom-config-evil-packages'. Then, for each package PACKAGE: 22 + ;; 23 + ;; - If PACKAGE is not referenced by any other Spacemacs layer, define a 24 + ;; function `custom-config-evil/init-PACKAGE' to load and initialize the package. 25 + 26 + ;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so 27 + ;; define the functions `custom-config-evil/pre-init-PACKAGE' and/or 28 + ;; `custom-config-evil/post-init-PACKAGE' to customize the package as it is loaded. 29 + 30 + ;;; Code: 31 + 32 + (defconst custom-config-evil-packages 33 + '(evil) 34 + ) 35 + 36 + (defun custom-config-evil/post-init-evil () 37 + (setq evil-search-module 'evil-search) 38 + ) 39 + 40 + 41 + ;;; packages.el ends here
+142
spacemacs-private/custom-config-org/packages.el
··· 1 + ;;; packages.el --- custom-config-org layer packages file for Spacemacs. 2 + ;; 3 + ;; Copyright (c) 2012-2018 Sylvain Benner & Contributors 4 + ;; 5 + ;; Author: Kaushik Chakraborty <kaushik@AMB00472> 6 + ;; URL: https://github.com/syl20bnr/spacemacs 7 + ;; 8 + ;; This file is not part of GNU Emacs. 9 + ;; 10 + ;;; License: GPLv3 11 + 12 + ;;; Commentary: 13 + 14 + ;; See the Spacemacs documentation and FAQs for instructions on how to implement 15 + ;; a new layer: 16 + ;; 17 + ;; SPC h SPC layers RET 18 + ;; 19 + ;; 20 + ;; Briefly, each package to be installed or configured by this layer should be 21 + ;; added to `custom-config-org-packages'. Then, for each package PACKAGE: 22 + ;; 23 + ;; - If PACKAGE is not referenced by any other Spacemacs layer, define a 24 + ;; function `custom-config-org/init-PACKAGE' to load and initialize the package. 25 + 26 + ;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so 27 + ;; define the functions `custom-config-org/pre-init-PACKAGE' and/or 28 + ;; `custom-config-org/post-init-PACKAGE' to customize the package as it is loaded. 29 + 30 + ;;; Code: 31 + 32 + (defconst custom-config-org-packages 33 + '(org) 34 + ) 35 + 36 + (defun custom-config-org/org-capture-templates () 37 + (setq org-capture-templates '(("m" "micro blog" 38 + plain 39 + (file (lambda () 40 + (expand-file-name (concat (format-time-string "%Y%m%d%H%M%S") 41 + ".md") 42 + "~/Developer/src/personal/blog-hakyll/micro-posts/"))) 43 + "---\npublished : %<%Y-%m-%d %H:%M:%S%z>\n---\n\n%c%?") 44 + ("n" "new note" 45 + item 46 + (file (lambda () 47 + (expand-file-name (concat "note-" 48 + (format-time-string "%Y%m%d%H%M%S") 49 + ".org") 50 + org-directory))) 51 + "**** \n- %?") 52 + ;; ("p" "new day plan" 53 + ;; plain 54 + ;; (file (lambda () 55 + ;; (expand-file-name (concat "plan-" 56 + ;; (format-time-string "%Y-%m-%d") 57 + ;; ".org") 58 + ;; "~/Documents/Org-Notes/Plans/"))) 59 + ;; "#+FILETAGS: planning daily\n* %^{item}\n %^{date}T\n - %?\n") 60 + ("t" "new todo" 61 + entry 62 + (file+headline "" "Tasks") 63 + "* TODO %?\n:PROPERTIES:\n:CREATEDON: %U\n:END:" :prepend t))) 64 + ) 65 + 66 + (defun custom-config-org/org-custom-commands () 67 + (setq org-agenda-custom-commands 68 + (quote 69 + (("A" "Priority #A tasks\"" agenda "" 70 + ((org-agenda-span 71 + (quote day)) 72 + (org-agenda-overriding-header "Today's priority #A tasks: ") 73 + (org-agenda-skip-function 74 + (quote 75 + (org-agenda-skip-entry-if 76 + (quote notregexp) 77 + "\\=.*\\[#A\\]"))))) 78 + ("b" "Priority #A and #B tasks" agenda "" 79 + ((org-agenda-span 80 + (quote day)) 81 + (org-agenda-overriding-header "Today's priority #A and #B tasks: ") 82 + (org-agenda-skip-function 83 + (quote 84 + (org-agenda-skip-entry-if 85 + (quote regexp) 86 + "\\=.*\\[#C\\]"))))) 87 + ("u" "Unscheduled tasks" tags "TODO<>\"\"&TODO<>{DONE\\|CANCELED\\|DEFERRED\\|SOMEDAY}" 88 + ((org-agenda-overriding-header "Unscheduled tasks: ") 89 + (org-agenda-skip-function 90 + (quote 91 + (org-agenda-skip-entry-if 92 + (quote scheduled) 93 + (quote deadline) 94 + ))) 95 + (org-agenda-sorting-strategy 96 + (quote 97 + (user-defined-up))) 98 + (org-agenda-prefix-format "%-11c%5(org-todo-age) "))) 99 + )))) 100 + 101 + (defun custom-config-org/post-init-org () 102 + (setq 103 + org-directory "/Users/kaushik/Documents/Org-Notes/" 104 + 105 + org-default-notes-file "/Users/kaushik/Library/Mobile Documents/iCloud~com~appsonthemove~beorg/Documents/Org-Notes/todo.org" 106 + 107 + org-agenda-files '( 108 + "/Users/kaushik/Documents/Org-Notes/" 109 + "/Users/kaushik/Library/Mobile Documents/iCloud~com~appsonthemove~beorg/Documents/Org-Notes/todo.org" 110 + ) 111 + 112 + org-todo-keywords '((sequence 113 + "TODO(t)" 114 + "STARTED(s@/!)" 115 + "WAITING(w@)" 116 + "|" 117 + "DONE(d!)" 118 + "SOMEDAY(y!)" 119 + "CANCELLED(c@)" 120 + "DEFERRED(r@)")) 121 + org-todo-keyword-faces (quote ( 122 + ("TODO" :foreground "#00BFFF" :weight bold) 123 + ("STARTED" :foreground "#FF8247" :weight bold) 124 + ("WAITING" :foreground "#EE6363" :weight bold) 125 + ("SOMEDAY" :foreground "#EEDC82" :weight bold) 126 + ("DEFERRED" :foreground "#4876FF" :weight bold) 127 + ("DONE" :foreground "#76EE00" :weight bold) 128 + )) 129 + 130 + org-pretty-entities t 131 + org-agenda-span 'day 132 + org-archive-location "TODO-archive::" 133 + org-archive-save-context-info (quote (time category itags)) 134 + ) 135 + 136 + (custom-config-org/org-capture-templates) 137 + (custom-config-org/org-custom-commands) 138 + (add-hook 'org-capture-mode-hook 139 + (lambda () 140 + (evil-insert-state))) 141 + ) 142 + ;;; packages.el ends here
+65
spacemacs-private/custom-direnv/packages.el
··· 1 + ;;; packages.el --- custom-direnv layer packages file for Spacemacs. 2 + ;; 3 + ;; Copyright (c) 2012-2018 Sylvain Benner & Contributors 4 + ;; 5 + ;; Author: Kaushik Chakraborty <kaushik@AMB00472.local> 6 + ;; URL: https://github.com/syl20bnr/spacemacs 7 + ;; 8 + ;; This file is not part of GNU Emacs. 9 + ;; 10 + ;;; License: GPLv3 11 + 12 + ;;; Commentary: 13 + 14 + ;; See the Spacemacs documentation and FAQs for instructions on how to implement 15 + ;; a new layer: 16 + ;; 17 + ;; SPC h SPC layers RET 18 + ;; 19 + ;; 20 + ;; Briefly, each package to be installed or configured by this layer should be 21 + ;; added to `custom-direnv-packages'. Then, for each package PACKAGE: 22 + ;; 23 + ;; - If PACKAGE is not referenced by any other Spacemacs layer, define a 24 + ;; function `custom-direnv/init-PACKAGE' to load and initialize the package. 25 + 26 + ;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so 27 + ;; define the functions `custom-direnv/pre-init-PACKAGE' and/or 28 + ;; `custom-direnv/post-init-PACKAGE' to customize the package as it is loaded. 29 + 30 + ;;; Code: 31 + 32 + (defconst custom-direnv-packages 33 + '(direnv 34 + flycheck)) 35 + 36 + (defun custom-direnv/patch-direnv-environment (&rest _args) 37 + (let ((emacs-bin (directory-file-name 38 + (file-name-directory 39 + (executable-find "emacsclient"))))) 40 + (setenv "PATH" (concat emacs-bin ":" (getenv "PATH"))) 41 + (setq exec-path (cons (file-name-as-directory emacs-bin) 42 + exec-path)))) 43 + 44 + (defun custom-direnv/init-direnv () 45 + (use-package direnv 46 + :defer t 47 + :config 48 + (advice-add 'direnv-update-directory-environment 49 + :after #'custom-direnv/patch-direnv-environment) 50 + )) 51 + 52 + (defun custom-direnv/post-init-flycheck () 53 + '(setq flycheck-executable-find 54 + (lambda (cmd) 55 + (add-hook 'post-command-hook #'direnv--maybe-update-environment) 56 + (direnv-update-environment default-directory) 57 + (executable-find cmd)))) 58 + 59 + (defun custom-direnv/post-init-direnv () 60 + (direnv-mode) 61 + (add-hook 'git-commit-mode-hook #'custom-direnv/patch-direnv-environment) 62 + ) 63 + 64 + 65 + ;;; packages.el ends here
+84
spacemacs-private/custom-haskell/packages.el
··· 1 + ;;; packages.el --- custom-haskell layer packages file for Spacemacs. 2 + ;; 3 + ;; Copyright (c) 2012-2018 Sylvain Benner & Contributors 4 + ;; 5 + ;; Author: Kaushik Chakraborty <kaushik@AMB00472.local> 6 + ;; URL: https://github.com/syl20bnr/spacemacs 7 + ;; 8 + ;; This file is not part of GNU Emacs. 9 + ;; 10 + ;;; License: GPLv3 11 + 12 + ;;; Commentary: 13 + 14 + ;; See the Spacemacs documentation and FAQs for instructions on how to implement 15 + ;; a new layer: 16 + ;; 17 + ;; SPC h SPC layers RET 18 + ;; 19 + ;; 20 + ;; Briefly, each package to be installed or configured by this layer should be 21 + ;; added to `custom-haskell-packages'. Then, for each package PACKAGE: 22 + ;; 23 + ;; - If PACKAGE is not referenced by any other Spacemacs layer, define a 24 + ;; function `custom-haskell/init-PACKAGE' to load and initialize the package. 25 + 26 + ;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so 27 + ;; define the functions `custom-haskell/pre-init-PACKAGE' and/or 28 + ;; `custom-haskell/post-init-PACKAGE' to customize the package as it is loaded. 29 + 30 + ;;; Code: 31 + 32 + (defconst custom-haskell-packages 33 + '() 34 + "The list of Lisp packages required by the custom-haskell layer. 35 + 36 + Each entry is either: 37 + 38 + 1. A symbol, which is interpreted as a package to be installed, or 39 + 40 + 2. A list of the form (PACKAGE KEYS...), where PACKAGE is the 41 + name of the package to be installed or loaded, and KEYS are 42 + any number of keyword-value-pairs. 43 + 44 + The following keys are accepted: 45 + 46 + - :excluded (t or nil): Prevent the package from being loaded 47 + if value is non-nil 48 + 49 + - :location: Specify a custom installation location. 50 + The following values are legal: 51 + 52 + - The symbol `elpa' (default) means PACKAGE will be 53 + installed using the Emacs package manager. 54 + 55 + - The symbol `local' directs Spacemacs to load the file at 56 + `./local/PACKAGE/PACKAGE.el' 57 + 58 + - A list beginning with the symbol `recipe' is a melpa 59 + recipe. See: https://github.com/milkypostman/melpa#recipe-format") 60 + 61 + 62 + ;;; packages.el ends here 63 + 64 + (defconst custom-haskell-packages 65 + '(haskell 66 + dante 67 + nix-sandbox)) 68 + 69 + (defun custom-haskell/post-init-haskell () 70 + (add-hook 'haskell-mode-hook 'turn-on-haskell-indentation) 71 + (add-hook 'haskell-mode-hook 'dante-mode) 72 + (spacemacs/set-leader-keys-for-major-mode 73 + 'haskell-mode "M-." 'xref-find-definitions) 74 + ) 75 + (defun custom-haskell/post-init-dante () 76 + (add-hook 'dante-mode-hook 77 + '(lambda () 78 + (flycheck-add-next-checker 'haskell-dante 79 + '(warning . haskell-hlint))))) 80 + 81 + (defun custom-haskell/post-init-nix-sandbox () 82 + (setq haskell-process-wrapper-function 83 + (lambda (args) (apply 'nix-shell-command (nix-current-sandbox) args))) 84 + )
+46
spacemacs-private/custom-lean/README.org
··· 1 + #+TITLE: custom-lean layer 2 + 3 + # The maximum height of the logo should be 200 pixels. 4 + [[img/custom-lean.png]] 5 + 6 + # TOC links should be GitHub style anchors. 7 + * Table of Contents :TOC_4_gh:noexport: 8 + - [[#description][Description]] 9 + - [[#features][Features:]] 10 + - [[#install][Install]] 11 + - [[#key-bindings][Key bindings]] 12 + 13 + * Description 14 + This layer adds support for [[https://leanprover.github.io/][Lean]] programming language. 15 + 16 + ** Features: 17 + - syntax highlighting 18 + - autocompletion via ~company-lean~ 19 + - searcheable list of options via ~helm-lean~ 20 + 21 + * Install 22 + To use this configuration layer, add it to your =~/.spacemacs=. You will need to 23 + add =custom-lean= to the existing =dotspacemacs-configuration-layers= list in this 24 + file. 25 + 26 + * Key bindings 27 + 28 + from [[https://github.com/leanprover/lean-mode][lean-mode]] 29 + 30 + | Key | Function | 31 + |--------------------|---------------------------------------------------------------------------------| 32 + | <kbd>M-.</kbd> | jump to definition in source file (`lean-find-definition`) | 33 + | <kbd>M-,</kbd> | jump back to position before <kbd>M-.</kbd> (`xref-pop-marker-stack`) | 34 + | <kbd>C-c C-k</kbd> | shows the keystroke needed to input the symbol under the cursor | 35 + | <kbd>C-c C-x</kbd> | execute lean in stand-alone mode (`lean-std-exe`) | 36 + | <kbd>C-c SPC</kbd> | run a command on the hole at point (`lean-hole`) | 37 + | <kbd>C-c C-d</kbd> | show a searchable list of definitions (`helm-lean-definitions`) | 38 + | <kbd>C-c C-g</kbd> | toggle showing current tactic proof goal (`lean-toggle-show-goal`) | 39 + | <kbd>C-c C-n</kbd> | toggle showing next error in dedicated buffer (`lean-toggle-next-error`) | 40 + | <kbd>C-c C-b</kbd> | toggle showing output in inline boxes (`lean-message-boxes-toggle`) | 41 + | <kbd>C-c C-r</kbd> | restart the lean server (`lean-server-restart`) | 42 + | <kbd>C-c C-s</kbd> | switch to a different Lean version via [elan](https://github.com/Kha/elan) (`lean-server-switch-version`) | 43 + | <kbd>C-c ! n</kbd> | flycheck: go to next error | 44 + | <kbd>C-c ! p</kbd> | flycheck: go to previous error | 45 + | <kbd>C-c ! l</kbd> | flycheck: show list of errors | 46 +
+59
spacemacs-private/custom-lean/packages.el
··· 1 + ;;; packages.el --- custom-lean layer packages file for Spacemacs. 2 + ;; 3 + ;; Copyright (c) 2012-2018 Sylvain Benner & Contributors 4 + ;; 5 + ;; Author: Kaushik Chakraborty <git@kaushikc.org> 6 + ;; URL: https://kaushikc.org 7 + ;; 8 + ;; This file is not part of GNU Emacs. 9 + ;; 10 + ;;; License: GPLv3 11 + 12 + ;;; Commentary: 13 + 14 + ;; See the Spacemacs documentation and FAQs for instructions on how to implement 15 + ;; a new layer: 16 + ;; 17 + ;; SPC h SPC layers RET 18 + ;; 19 + ;; 20 + ;; Briefly, each package to be installed or configured by this layer should be 21 + ;; added to `custom-lean-packages'. Then, for each package PACKAGE: 22 + ;; 23 + ;; - If PACKAGE is not referenced by any other Spacemacs layer, define a 24 + ;; function `custom-lean/init-PACKAGE' to load and initialize the package. 25 + 26 + ;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so 27 + ;; define the functions `custom-lean/pre-init-PACKAGE' and/or 28 + ;; `custom-lean/post-init-PACKAGE' to customize the package as it is loaded. 29 + 30 + ;;; Code: 31 + 32 + (defconst custom-lean-packages 33 + '( 34 + lean-mode 35 + (company-lean :requires company) 36 + (helm-lean :requires helm) 37 + )) 38 + 39 + (defun custom-lean/init-lean-mode () 40 + (use-package lean-mode 41 + :defer t)) 42 + 43 + (defun custom-lean/post-init-company ()) 44 + 45 + (defun custom-lean/init-company-lean () 46 + (use-package company-lean 47 + :defer t 48 + :init 49 + (spacemacs|add-company-backends 50 + :backends company-lean 51 + :modes lean-mode) 52 + )) 53 + 54 + (defun custom-lean/init-helm-lean () 55 + (use-package helm-lean 56 + :defer t)) 57 + 58 + 59 + ;;; packages.el ends here
+58
spacemacs-private/custom-nix/packages.el
··· 1 + ;;; packages.el --- custom-nix layer packages file for Spacemacs. 2 + ;; 3 + ;; Copyright (c) 2012-2018 Sylvain Benner & Contributors 4 + ;; 5 + ;; Author: Kaushik Chakraborty <kaushik@AMB00472> 6 + ;; URL: https://github.com/syl20bnr/spacemacs 7 + ;; 8 + ;; This file is not part of GNU Emacs. 9 + ;; 10 + ;;; License: GPLv3 11 + 12 + ;;; Commentary: 13 + 14 + ;; See the Spacemacs documentation and FAQs for instructions on how to implement 15 + ;; a new layer: 16 + ;; 17 + ;; SPC h SPC layers RET 18 + ;; 19 + ;; 20 + ;; Briefly, each package to be installed or configured by this layer should be 21 + ;; added to `custom-nix-packages'. Then, for each package PACKAGE: 22 + ;; 23 + ;; - If PACKAGE is not referenced by any other Spacemacs layer, define a 24 + ;; function `custom-nix/init-PACKAGE' to load and initialize the package. 25 + 26 + ;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so 27 + ;; define the functions `custom-nix/pre-init-PACKAGE' and/or 28 + ;; `custom-nix/post-init-PACKAGE' to customize the package as it is loaded. 29 + 30 + ;;; Code: 31 + 32 + (defconst custom-nix-packages 33 + '(nix-mode 34 + nix-sandbox 35 + persp-mode) 36 + ) 37 + 38 + (defun custom-nix/init-nix-mode () 39 + (use-package nix-mode 40 + :defer t 41 + :mode ("\\.nix\\'" "\\.nix.in\\'") 42 + :init 43 + (setq nix-indent-function 'nix-indent-line) 44 + )) 45 + 46 + (defun custom-nix/init-nix-sandbox () 47 + (use-package nix-sandbox 48 + :defer t)) 49 + 50 + (defun custom-nix/post-init-persp-mode() 51 + (spacemacs|define-custom-layout "@Nix-Config" 52 + :binding "n" 53 + :body 54 + (progn 55 + (find-file "~/Developer/src/personal/nix-config/darwin.nix") 56 + (find-file-other-window "~/Developer/src/personal/nixpkgs/pkgs/top-level/all-packages.nix")))) 57 + 58 + ;;; packages.el ends here
+53
spacemacs-private/custom-super-save/packages.el
··· 1 + ;;; packages.el --- custom-super-save layer packages file for Spacemacs. 2 + ;; 3 + ;; Copyright (c) 2012-2018 Sylvain Benner & Contributors 4 + ;; 5 + ;; Author: Kaushik Chakraborty <git@kaushikc.org> 6 + ;; URL: https://kaushikc.org 7 + ;; 8 + ;; This file is not part of GNU Emacs. 9 + ;; 10 + ;;; License: GPLv3 11 + 12 + ;;; Commentary: 13 + 14 + ;; See the Spacemacs documentation and FAQs for instructions on how to implement 15 + ;; a new layer: 16 + ;; 17 + ;; SPC h SPC layers RET 18 + ;; 19 + ;; 20 + ;; Briefly, each package to be installed or configured by this layer should be 21 + ;; added to `custom-super-save-packages'. Then, for each package PACKAGE: 22 + ;; 23 + ;; - If PACKAGE is not referenced by any other Spacemacs layer, define a 24 + ;; function `custom-super-save/init-PACKAGE' to load and initialize the package. 25 + 26 + ;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so 27 + ;; define the functions `custom-super-save/pre-init-PACKAGE' and/or 28 + ;; `custom-super-save/post-init-PACKAGE' to customize the package as it is loaded. 29 + 30 + ;;; Code: 31 + 32 + (defconst custom-super-save-packages 33 + '(super-save) 34 + ) 35 + (defun custom-super-save/init-super-save () 36 + (use-package super-save 37 + :defer t 38 + :config 39 + (super-save-mode +1) 40 + (setq auto-save-default t) 41 + (setq super-save-remote-files nil) 42 + (setq super-save-auto-save-when-idle t) 43 + )) 44 + 45 + (defun custom-super-save/post-init-super-save () 46 + (super-save-mode +1) 47 + (setq auto-save-default t) 48 + (setq super-save-remote-files nil) 49 + (setq super-save-auto-save-when-idle t) 50 + ) 51 + 52 + 53 + ;;; packages.el ends here
+6
spacemacs-private/local/README.md
··· 1 + # Private directory for local packages 2 + 3 + The content of this directory is ignored by Git. 4 + 5 + This is the place to store the local packages that you define in 6 + the `dotspacemacs-additional-packages` variable of your dotfile.
+2123
spacemacs-private/local/beeminder.el
··· 1 + ;;; beeminder.el --- Emacs client for Beeminder -*- lexical-binding: t; -*- 2 + 3 + ;; Copyright (C) 2015 Marcin 'mbork' Borkowski 4 + 5 + ;; Author: Marcin Borkowski <mbork@mbork.pl> 6 + ;; Keywords: calendar 7 + ;; Package-Requires: ((request "0.2.0")) 8 + 9 + ;; This file is NOT part of GNU Emacs. 10 + 11 + ;; beeminder.el is free software: you can redistribute it and/or modify 12 + ;; it under the terms of the GNU General Public License as published by 13 + ;; the Free Software Foundation, either version 3 of the License, or 14 + ;; (at your option) any later version. 15 + 16 + ;; beeminder.el is distributed in the hope that it will be useful, 17 + ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 18 + ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 + ;; GNU General Public License for more details. 20 + 21 + ;; You should have received a copy of the GNU General Public License 22 + ;; along with beeminder.el. 23 + ;; If not, see <http://www.gnu.org/licenses/>. 24 + 25 + ;;; Commentary: 26 + ;; beeminder.el is an Emacs client for the Beeminder service. 27 + ;; Beeminder (taglined "a reminder with a sting") is 28 + ;; a motivation/quantified self tool based on behavioral economics 29 + ;; principles. 30 + 31 + (require 'json) 32 + (require 'request) 33 + (if (>= emacs-major-version 24) 34 + (progn 35 + (require 'cl-lib) 36 + (require 'anaphora) 37 + (defalias 'increasingp '<)) 38 + (require 'cl) 39 + (defalias 'cl-reduce 'reduce) 40 + (defalias 'cl-find 'find) 41 + (defalias 'cl-incf 'incf) 42 + (defalias 'cl-decf 'decf) 43 + (defalias 'cl-case 'case) 44 + (defalias 'cl-delete 'delete*) 45 + (defmacro setq-local (var val) 46 + "This is taken from subr.el." 47 + `(set (make-local-variable ',var) ,val)) 48 + (defmacro aif (cond then &rest else) 49 + `(let ((it ,cond)) 50 + (if it ,then ,@else))) 51 + (defmacro awhen (cond &rest body) 52 + `(aif ,cond 53 + (progn ,@body))) 54 + (defun increasingp (&rest args) 55 + "Return t if ARGS are in increasing order." 56 + (if (cdr args) 57 + (and (< (car args) (cadr args)) 58 + (apply #' increasingp (cdr args))) 59 + t))) 60 + (require 'ewoc) 61 + 62 + ;;; Code: 63 + 64 + 65 + ;; Utilities 66 + (defun trim-leading-whitespace (string) 67 + "Trim tabs and spaces from the beginning of STRING." 68 + (when (string-match "^[ \t]*" string) 69 + (replace-match "" nil nil string))) 70 + 71 + (defun beeminder-alist-get (key alist) 72 + "Return the value associated to KEY in ALIST. 73 + This function is needed for Emacsen older than v25." 74 + (cdr (assoc key alist))) 75 + 76 + (defun beeminder-set-alist-value (key alist value) 77 + "Set the value corresponding to KEY in ALIST to VALUE. 78 + Note: ALIST should be a symbol. This is morally equivalent to 79 + `(setf (alist-get key (symbol-value alist)) value)', 80 + but works in older Emacsen." 81 + (let ((pair (assoc key (symbol-value alist)))) 82 + (if pair 83 + (setcdr pair value) 84 + (set alist (acons key value (symbol-value alist)))))) 85 + 86 + (defun beeminder-inc-alist-value (key alist increment) 87 + "Increment the value corresponding to KEY in ALIST by INCREMENT. 88 + Throw an error if KEY is not in ALIST." 89 + (let ((pair (assoc key alist))) 90 + (if pair 91 + (incf (cdr pair) increment) 92 + (error "Nothing to increment")))) 93 + 94 + (defun beeminder-to-list (sequence) 95 + "Turn SEQUENCE into a list." 96 + (append sequence nil)) 97 + 98 + 99 + ;; Settings 100 + 101 + (defgroup beeminder nil 102 + "An Emacs client for Beeminder." 103 + :group 'applications) 104 + 105 + (defcustom beeminder-username "" 106 + "User name for the Beeminder account." 107 + :type 'string 108 + :group 'beeminder) 109 + 110 + (defcustom beeminder-auth-token "" 111 + "Authentication token for Beeminder. 112 + You can retrieve it from the URL 113 + `https://www.beeminder.com/api/v1/auth_token.json'." 114 + :type 'string 115 + :group 'beeminder) 116 + 117 + (defcustom beeminder-api-url "https://www.beeminder.com/api/v1/users/" 118 + "The URL for making API calls." 119 + :type 'string 120 + :group 'beeminder) 121 + 122 + (defvar beeminder-goals nil 123 + "The list of sexps representing goals. 124 + Updated by `beeminder-get-goals'.") 125 + 126 + (defcustom beeminder-default-timeout 30 127 + "Default timeout for HTTP requests sent to beeminder, in seconds." 128 + :type 'number 129 + :group 'beeminder) 130 + 131 + 132 + ;; Beeminder mode 133 + 134 + (define-derived-mode beeminder-mode special-mode "Beeminder" 135 + "A major mode for a buffer with Beeminder goal list.") 136 + 137 + (defun next-goal (count) 138 + "Move COUNT goals forward in the Beeminder buffer." 139 + (interactive "p") 140 + (ewoc-goto-next beeminder-goals-ewoc 141 + (if (beeminder-before-first-goal-p) 142 + (1- count) 143 + count))) 144 + 145 + (defun previous-goal (count) 146 + "Move COUNT goals back in the Beeminder buffer. 147 + If on the first goal, move to (point-min)." 148 + ;; If point is before the place `previous-goal' would move it, move 149 + ;; to (point-min). This jumps to the beginning from any place 150 + ;; before the first node, but won't work when point is on Nth goal 151 + ;; and `count' is greater than N. This doesn't seem a big deal, so 152 + ;; let's just hope nobody notices that. 153 + (interactive "p") 154 + (when (<= (point) 155 + (progn (ewoc-goto-prev beeminder-goals-ewoc count) 156 + (point))) 157 + (goto-char (point-min)))) 158 + 159 + (define-key beeminder-mode-map (kbd "n") #'next-goal) 160 + (define-key beeminder-mode-map (kbd "p") #'previous-goal) 161 + 162 + 163 + ;; API interface 164 + 165 + (defun beeminder-create-api-url (string) 166 + "Prepend Beeminder site address and the username to STRING. 167 + STRING should begin with a slash." 168 + (concat beeminder-api-url beeminder-username string)) 169 + 170 + (defun beeminder-request-get (request &optional params success-fun error-fun timeout) 171 + "Send a GET REQUEST to beeminder.com, with TIMEOUT. 172 + Add the necessary details (including the username and the auth 173 + token)." 174 + (request (beeminder-create-api-url request) 175 + :parser #'json-read 176 + :params (append params (list (cons "auth_token" beeminder-auth-token))) 177 + :success success-fun 178 + :error error-fun 179 + :timeout (or timeout beeminder-default-timeout))) 180 + 181 + (defun beeminder-request-post (request data success-fun error-fun &optional timeout) 182 + "Send a POST REQUEST with given DATA and TIMEOUT to beeminder.com. 183 + Add the username and the auth token." 184 + (request (beeminder-create-api-url request) 185 + :type "POST" 186 + :data (append data 187 + (list (cons "auth_token" beeminder-auth-token))) 188 + :parser #'json-read 189 + :success success-fun 190 + :error error-fun 191 + :timeout (or timeout beeminder-default-timeout))) 192 + 193 + (defun beeminder-request-delete (request success-fun error-fun &optional timeout) 194 + "Send a DELETE request to beeminder.com, with TIMEOUT. 195 + Add the necessary details (username and the auth token)." 196 + (request-response-data 197 + (request (concat (beeminder-create-api-url request)) 198 + :params (list (cons "auth_token" beeminder-auth-token)) 199 + :type "DELETE" 200 + :parser #'json-read 201 + :success success-fun 202 + :error error-fun 203 + :timeout (or timeout beeminder-default-timeout)))) 204 + 205 + (defun beeminder-request-put (request data success-fun error-fun &optional timeout) 206 + "Send a PUT request to beeminder.com, with TIMEOUT. 207 + Add the necessary details (username and the auth token)." 208 + (request-response-data 209 + (request (beeminder-create-api-url request) 210 + :type "PUT" 211 + :data (append data 212 + (list (cons "auth_token" beeminder-auth-token))) 213 + :parser #'json-read 214 + :success success-fun 215 + :error error-fun 216 + :timeout (or timeout beeminder-default-timeout)))) 217 + 218 + 219 + ;; API calls 220 + 221 + (defun last-goal-midnight (goal-deadline now) ; TODO: maybe refactor using beeminder-determine-date! 222 + "Return the last \"midnight\" for GOAL-DEADLINE, counting from NOW. 223 + GOAL-DEADLINE is an offset from real midnight in seconds, NOW is 224 + a time value." 225 + (let* ((now-decoded (decode-time now)) 226 + (last-real-midnight (encode-time 0 0 0 227 + (cadddr now-decoded) 228 + (nth 4 now-decoded) 229 + (nth 5 now-decoded) 230 + (nth 8 now-decoded))) 231 + (last-midnight (+ goal-deadline 232 + (if (< goal-deadline 0) (* 24 60 60) 0) 233 + (time-to-seconds last-real-midnight)))) 234 + (if (> last-midnight 235 + (time-to-seconds now)) 236 + (- last-midnight (* 24 60 60)) 237 + last-midnight))) 238 + 239 + (defun last-user-midnight (now) ; TODO: maybe refactor using beeminder-determine-date! 240 + "Return the last \"midnight\" counting from NOW, as Unix timestamp. 241 + Take `beeminder-when-the-day-ends' into consideration." 242 + (let* ((now-decoded (decode-time now)) 243 + (last-real-midnight (encode-time 0 0 0 244 + (cadddr now-decoded) 245 + (nth 4 now-decoded) 246 + (nth 5 now-decoded) 247 + (nth 8 now-decoded))) 248 + (last-midnight (+ (time-to-seconds last-real-midnight) 249 + beeminder-when-the-day-ends))) 250 + (if (> last-midnight (time-to-seconds now)) 251 + (- last-midnight (* 24 60 60)) 252 + last-midnight))) 253 + 254 + (defcustom beeminder-history-length 7 255 + "Number of days from which to load datapoints.") 256 + 257 + (defun beeminder-sum-today-value (datapoints start-time stop-time) 258 + "Sum the value for DATAPOINTS between START-TIME and STOP-TIME." 259 + (cl-reduce #'+ 260 + (mapcar (lambda (datapoint) 261 + (if (< start-time 262 + (cdr (assoc 'timestamp datapoint)) 263 + stop-time) 264 + (cdr (assoc 'value datapoint)) 265 + 0)) 266 + datapoints))) 267 + 268 + (defun beeminder-get-goals () 269 + "Get all the user's Beeminder goals and put them in the 270 + `beeminder-goals' variable." 271 + (beeminder-log "fetching goals...") 272 + (beeminder-request-get 273 + "/goals.json" 274 + () 275 + (cl-function (lambda (&key data &allow-other-keys) 276 + (beeminder-log "fetching goals.......") 277 + (let ((goals (beeminder-to-list data)) 278 + (now (beeminder-current-time))) 279 + (beeminder-request-get 280 + ".json" 281 + (list 282 + (cons "diff_since" 283 + (number-to-string 284 + (- (last-user-midnight now) 285 + (* beeminder-history-length 24 60 60))))) 286 + (cl-function (lambda (&key data &allow-other-keys) 287 + (let* ((datapoints ; extract datapoints alone 288 + (mapcar 289 + (lambda (goal) ; extract datapoints from a goal from data from API 290 + (cons (beeminder-alist-get 'slug goal) 291 + (beeminder-to-list (beeminder-alist-get 'datapoints goal)))) 292 + (cdr (assoc 'goals data)))) 293 + (deadlines ; deadlines alone 294 + (mapcar 295 + (lambda (goal) 296 + (cons (cdr (assoc 'slug goal)) 297 + (cdr (assoc 'deadline goal)))) 298 + goals)) 299 + (today-values 300 + (mapcar 301 + (lambda (goal) 302 + (let ((last-midnight (if beeminder-use-goal-midnight-today-values 303 + (last-goal-midnight (cdr (assoc (car goal) deadlines)) 304 + now) 305 + (last-user-midnight now)))) 306 + (cons (car goal) 307 + (beeminder-sum-today-value (cdr goal) last-midnight (time-to-seconds now))))) 308 + datapoints))) 309 + (cl-flet ((beeminder-join-goal-data (goal) 310 + "Join GOAL data from various sources." 311 + (let ((slug-str (cdr (assoc 'slug goal)))) 312 + (append (list (cons 'datapoints 313 + (cdr (assoc slug-str datapoints))) 314 + (cons 'donetoday 315 + (cdr (assoc 316 + (cdr (assoc 'slug goal)) 317 + today-values))) 318 + (cons 'history-length beeminder-history-length)) 319 + goal)))) 320 + (setq beeminder-goals (mapcar #'beeminder-join-goal-data goals)) 321 + (mapc #'beeminder-clean-goal goals) 322 + (beeminder-log "fetching goals...done") 323 + (setq beeminder-reloading-in-progress nil))))) 324 + #'beeminder-report-fetching-error)))) 325 + #'beeminder-report-fetching-error)) 326 + 327 + (defun beeminder-clean-goal (goal) 328 + "Remove GOAL from `beeminder-dirty-alist' if needed. 329 + The heuristics for that is simple: if the current curval is 330 + different than the one recorded in that list, remove it." 331 + (let ((slug (intern (cdr (assoc 'slug goal))))) 332 + (if (and (cdr (assoc slug beeminder-dirty-alist)) 333 + (/= (cdr (assoc 'curval goal)) 334 + (cdr (assoc slug beeminder-dirty-alist)))) 335 + (setq beeminder-dirty-alist (assq-delete-all slug beeminder-dirty-alist))))) 336 + 337 + (cl-defun beeminder-report-fetching-error (&key error-thrown &allow-other-keys) 338 + "Report ERROR-THROWN when fetching goals." 339 + (beeminder-log (format "fetching goals...error: %s" error-thrown)) 340 + (setq beeminder-reloading-in-progress nil)) 341 + 342 + (defun beeminder-refresh-goal (slug-str) 343 + "Refresh autodata and graph of the goal named SLUG-STR. 344 + Please do not use unless really necessary, since it creates 345 + a considerable server load." 346 + (interactive (list (cdr (assoc 'slug (current-or-read-goal))))) 347 + (beeminder-request-get (concat "/goals/" slug-str "/refresh_graph.json") 348 + nil 349 + (cl-function (lambda (&rest _) 350 + (beeminder-log 351 + (format 352 + "goal %s refreshed" 353 + slug-str)))) 354 + (cl-function (lambda (&rest _) 355 + (beeminder-log 356 + (format 357 + "goal %s could not be refreshed" 358 + slug-str)))))) 359 + 360 + (define-key beeminder-mode-map (kbd "G") #'beeminder-refresh-goal) 361 + 362 + 363 + ;; Submitting datapoints 364 + 365 + (defun beeminder-read-string (prompt &optional initial-input history default-value inherit-input-method) 366 + "Replacement for `read-string', showing the default." 367 + (read-string (if default-value 368 + (format "%s (default %s): " 369 + (if (string-match "^\\(.+\\)\\(: \\)$" prompt) 370 + (match-string 1 prompt) 371 + prompt) 372 + default-value) 373 + prompt) 374 + initial-input history default-value inherit-input-method)) 375 + 376 + (defun beeminder-before-first-goal-p () 377 + "Return t if the point is before the first goal or if there is 378 + no first goal." 379 + (aif (ewoc-nth beeminder-goals-ewoc 0) 380 + (< (point) 381 + (ewoc-location it)) 382 + t)) 383 + 384 + (defun beeminder-get-slug (goal) 385 + "Return the slug of GOAL." 386 + (intern (cdr (assoc 'slug goal)))) 387 + 388 + (defun beeminder-slug-to-goal (slug) 389 + "Return the goal corresponding to SLUG." 390 + (cl-find slug beeminder-goals :key #'beeminder-get-slug)) 391 + 392 + (defun beeminder-slug-to-gnode (slug) 393 + "Return the goal node corresponding to SLUG." 394 + (let ((gnode (ewoc-nth beeminder-goals-ewoc 0))) 395 + (while (and gnode 396 + (not 397 + (eq slug (beeminder-get-slug (ewoc-data gnode))))) 398 + (setq gnode (ewoc-next beeminder-goals-ewoc gnode))) 399 + gnode)) 400 + 401 + (defvar beeminder-minibuffer-history nil 402 + "History of goal slug-strs entered through minibuffer.") 403 + 404 + (defun beeminder-read-slug (&optional default) 405 + "Return a slug read from minibuffer or DEFAULT. 406 + DEFAULT should be a symbol." 407 + (intern (completing-read (if default 408 + (format "Goal slug (default %s): " default) 409 + "Goal slug: ") 410 + (mapcar (lambda (goal) 411 + (symbol-name (beeminder-get-slug goal))) 412 + beeminder-goals) 413 + nil 414 + t 415 + nil 416 + 'beeminder-minibuffer-history 417 + (if default (symbol-name default))))) 418 + 419 + (defun current-or-read-goal () 420 + "Return the goal the point is on. 421 + If the point is before the first goal or in a buffer whose mode 422 + is not `beeminder-mode', use `beeminder-read-slug' to ask for the 423 + goal slug and return that goal instead." 424 + (if (or (not (eq major-mode 'beeminder-mode)) 425 + (beeminder-before-first-goal-p)) 426 + (let ((default (aif (ewoc-nth beeminder-goals-ewoc 0) 427 + (beeminder-get-slug (ewoc-data it))))) 428 + (beeminder-slug-to-goal 429 + (beeminder-read-slug default))) 430 + (ewoc-data (ewoc-locate beeminder-goals-ewoc)))) 431 + 432 + (defcustom beeminder-time-format "%FT%T%z" 433 + "Default time format for Beeminder comments.") 434 + 435 + (defun beeminder-current-time-string (&optional timestamp) 436 + "Return TIMESTAMP (Unix time) as a string. 437 + Use current time by default. Format is hh:mm:ss tz." 438 + (format-time-string beeminder-time-format 439 + (or timestamp (beeminder-current-time)))) 440 + 441 + (defvar beeminder-dirty-alist '() 442 + "Alist of slugs and \"curval\" values of changed goals. 443 + A goal is put here by `beeminder-submit-datapoint' and cleared 444 + from the list by `beeminder-get-goals' (if the retrieved data are 445 + actually updated, which can take from a few seconds to even a few 446 + minutes).") 447 + 448 + (defgroup beeminder-faces nil 449 + "Faces used be the Beeminder client." 450 + :group 'beeminder) 451 + 452 + (defface beeminder-dirty '((t :slant italic :foreground "grey50")) 453 + "Face for displaying \"dirty\" goals, i.e., goals for which 454 + a datapoint was submitted but had ot yet been reloaded." 455 + :group 'beeminder-faces) 456 + 457 + (defun ask-for-timestamp (&optional default) 458 + "Ask the user for the timestamp, and return it as Unix time. 459 + If `org-read-date' is present, use that; if not, fall back to 460 + `safe-date-to-time' and augment the result with current time." 461 + (time-to-seconds 462 + (if (fboundp 'org-read-date) 463 + (org-read-date t t nil nil (beeminder-safe-time default)) 464 + (let (time) 465 + (while 466 + (progn (setq time (safe-date-to-time (beeminder-read-string "Date+time: "))) 467 + (not 468 + (y-or-n-p 469 + (format-time-string "Time entered: %c. Confirm? " time))))) 470 + time)))) 471 + 472 + (defun beeminder-default-comment (&optional timestamp) 473 + "Generate the default comment for the given TIMESTAMP." 474 + (concat 475 + "via Emacs at " 476 + (beeminder-current-time-string timestamp))) 477 + 478 + (defun beeminder-ask-for-comment (slug-str amount &optional default-comment) 479 + "Ask the user for the comment for the goal named SLUG-STR. 480 + Include AMOUNT in the question, and default to DEFAULT-COMMENT." 481 + (beeminder-read-string 482 + (format "Comment for amount %s for goal %s: " (number-to-human-string amount) slug-str) 483 + nil nil default-comment)) 484 + 485 + (defcustom beeminder-ask-for-comment t 486 + "Non-nil means ask for comment when a goal is submitted. 487 + This also serves as a confirmation that the user actually wants 488 + to submit data to Beeminder (especially that the question 489 + includes the goal slug and amount), so disabling of this option 490 + is discouraged.") 491 + 492 + (defun beeminder-make-goal-dirty (slug) 493 + "Make the goal with SLUG dirty." 494 + (beeminder-set-alist-value slug 495 + 'beeminder-dirty-alist 496 + (cdr (assoc 'curval (beeminder-slug-to-goal slug)))) 497 + (aif (beeminder-slug-to-gnode slug) 498 + (ewoc-invalidate beeminder-goals-ewoc it))) 499 + 500 + (defun beeminder-clear-dirty-goals () 501 + "Clear all dirty goals manually. 502 + This may be needed in rare circumstances, namely when 503 + successfully submitting a datapoint of 0." 504 + (interactive) 505 + (setq beeminder-dirty-alist ()) 506 + (save-current-goal 507 + (ewoc-refresh beeminder-goals-ewoc))) 508 + 509 + (defun beeminder-submit-datapoint (slug-str value &optional comment timestamp id) 510 + "Submit a datapoint to Beeminder goal SLUG-STR with AMOUNT. 511 + Additional data are COMMENT and TIMESTAMP (as Unix time). If 512 + COMMENT is nil, then ask the user for the comment. If TIMESTAMP 513 + is nil, assume now. If PRINT-MESSAGE is non-nil, print suitable 514 + messages in the echo area. If ID is non-nil, use it as requestid. 515 + 516 + If called interactively, ask for SLUG-STR (with completion) unless the 517 + point is on a goal node. Then, ask for AMOUNT unless the user 518 + provided a numeric argument, in which case take the argument. Then, 519 + ask for COMMENT, proposing a reasonable default, unless the option 520 + `beeminder-ask-for-comment' is nil. If called with a prefix argument 521 + of \\[universal-argument], ask also for TIMESTAMP. If called with 522 + a prefix argument of `-', use previous day as the TIMESTAMP." 523 + (interactive 524 + (let* ((slug-str (cdr (assoc 'slug (current-or-read-goal)))) 525 + (yesterdayp (eq current-prefix-arg '-)) 526 + (value (if (numberp current-prefix-arg) 527 + current-prefix-arg 528 + (string-to-number (beeminder-read-string 529 + (format "Datapoint value for %s%s: " 530 + slug-str 531 + (if yesterdayp " (yesterday)" "")) 532 + nil nil "1")))) 533 + (current-timestamp (time-to-seconds (beeminder-current-time)))) 534 + (list slug-str 535 + value 536 + (unless beeminder-ask-for-comment 537 + (beeminder-default-comment current-timestamp)) 538 + (or (when yesterdayp 539 + (- current-timestamp (* 24 60 60))) 540 + (when (consp current-prefix-arg) 541 + (ask-for-timestamp)) 542 + current-timestamp)))) 543 + (let ((timestamp (or timestamp (time-to-seconds (beeminder-current-time))))) 544 + (beeminder-log (format "submitting datapoint of %s for goal %s..." 545 + (number-to-human-string value) 546 + slug-str)) 547 + (beeminder-request-post (format "/goals/%s/datapoints.json" slug-str) 548 + (list 549 + (cons "value" (format "%f" value)) 550 + (cons "comment" (or comment (beeminder-ask-for-comment 551 + slug-str 552 + value 553 + (beeminder-default-comment timestamp)))) 554 + (if id (cons "requestid" id)) 555 + (cons "timestamp" (format "%s" timestamp))) 556 + (cl-function (lambda (&rest _) 557 + (beeminder-log (format "submitting datapoint of %s for goal %s...done" 558 + (number-to-human-string value) 559 + slug-str)) 560 + (let* ((slug (intern slug-str)) 561 + (goal (beeminder-slug-to-goal slug))) 562 + (when goal 563 + (beeminder-inc-alist-value 'donetoday goal value) 564 + (beeminder-make-goal-dirty slug))))) 565 + (cl-function (lambda (&rest _) 566 + (beeminder-log 567 + (format "submitting datapoint of %s for goal %s...failed" 568 + (number-to-human-string value) 569 + slug-str) 570 + :error)))))) 571 + 572 + (define-key beeminder-mode-map (kbd "RET") #'beeminder-submit-datapoint) 573 + 574 + 575 + ;; Sorting EWOC 576 + 577 + (defun true (&rest args) 578 + "Always return t (irrespective of ARGS)." 579 + t) 580 + 581 + (defun ewoc-sort (ewoc pred) 582 + "Sort EWOC, comparing its nodes using PRED. 583 + Since the author of EWOC didn't really care for sorting, and 584 + neither do I, we just first collect the nodes into a list, sort 585 + it using Elisp's sort, and then recreate the EWOC." 586 + (let ((ewoc-list (ewoc-collect ewoc #'true))) 587 + (ewoc-filter ewoc #'ignore) 588 + (mapcar (lambda (node) (ewoc-enter-last ewoc node)) 589 + (sort ewoc-list pred)))) 590 + 591 + 592 + ;; Logging 593 + (define-derived-mode beeminder-log-mode special-mode "Beeminder log" 594 + "A major mode for logging beeminder.el actions.") 595 + 596 + (defface beeminder-error '((t :foreground "#800" :weight bold)) 597 + "Face for displaying error notifications.") 598 + 599 + (defface beeminder-warning '((t :foreground "#880" :weight bold)) 600 + "Face for displaying warning notifications.") 601 + 602 + (defcustom beeminder-notification-expire-time 8 603 + "After that many seconds less important notifications expire. 604 + TODO: not yet implemented." 605 + :type 'integer 606 + :group 'beeminder) 607 + 608 + (defvar beeminder-notification-expiration-timer nil 609 + "Timer used to clear notifications after 610 + `beeminder-notification-expire-time'.") 611 + 612 + (defun beeminder-log (message &optional level) 613 + "Put MESSAGE into the log and possibly into the notification 614 + area. LEVEL can be `:error', `:warning', `:logonly' or `:nolog'. 615 + Messages without any of these levels expire after 616 + `beeminder-notification-expire-time' seconds." 617 + (let ((level-string (cl-case level 618 + (:error " error") 619 + (:warning " warning") 620 + (t "")))) 621 + (unless (eq level :nolog) 622 + (save-excursion 623 + (setq message (subst-char-in-string ?\n ?\s message t)) 624 + (set-buffer (get-buffer-create "*Beeminder log*")) 625 + (beeminder-log-mode) 626 + (goto-char (point-max)) 627 + (let ((inhibit-read-only t)) 628 + (insert (current-time-string) level-string ": " message "\n")))) 629 + (unless (eq level :logonly) 630 + (message "Beeminder%s: %s" 631 + level-string 632 + message) 633 + (setq beeminder-notification 634 + (cond ((eq level :error) 635 + (propertize message 'face 'beeminder-error)) 636 + ((eq level :warning) 637 + (propertize message 'face 'beeminder-warning)) 638 + (t message)))) 639 + (awhen beeminder-notification-expiration-timer (cancel-timer it)) 640 + (unless (memq level '(:error :warning)) 641 + (setq beeminder-notification-expiration-timer 642 + (run-at-time beeminder-notification-expire-time nil #'beeminder-clear-notification))) 643 + (when beeminder-goals-ewoc (beeminder-refresh-goals-list)))) 644 + 645 + (defun beeminder-clear-notification () 646 + "Clear the notification." 647 + (interactive) 648 + (setq beeminder-notification nil) 649 + (beeminder-refresh-goals-list)) 650 + 651 + (define-key beeminder-mode-map (kbd "C") #'beeminder-clear-notification) 652 + 653 + (defvar beeminder-notification nil 654 + "A message that should appear right below the header in 655 + Beeminder mode.") 656 + 657 + (defun beeminder-pop-log () 658 + "Pop the Beeminder log buffer." 659 + (interactive) 660 + (pop-to-buffer "*Beeminder log*")) 661 + 662 + (define-key beeminder-mode-map (kbd "L") #'beeminder-pop-log) 663 + 664 + 665 + ;; Displaying goals 666 + 667 + (defvar beeminder-human-time-use-weekday t 668 + "Non-nil means that `beeminder-human-time' uses weekday names. 669 + Otherwise, use number of days from today.") 670 + 671 + (defvar beeminder-tomorrow-code "tom" 672 + "The abbreviation for \"tomorrow\".") 673 + 674 + (defcustom beeminder-when-the-day-ends (* 6 60 60) 675 + "Number of seconds from midnight when the day is assumed to end. 676 + Times up to this time will be considered to belong to the 677 + previous day. Note: this should be positive, or weird things 678 + might happen." 679 + :type 'integer 680 + :group 'beeminder) 681 + 682 + (defun beeminder-plural-ending (number) 683 + "Return \"s\" if NUMBER not equal to one, and \"\" otherwise." 684 + (if (= number 1) "" "s")) 685 + 686 + (defun beeminder-safe-time (time) 687 + "Convert TIME to Emacs time format if it is a number." 688 + (if (numberp time) 689 + (seconds-to-time time) 690 + time)) 691 + 692 + (defun beeminder-time-to-days (time) 693 + "Compute the number of days from 0001-12-31 BC until TIME. 694 + Take into consideration `beeminder-when-the-day-ends'." 695 + (time-to-days 696 + (time-add (beeminder-safe-time time) 697 + (seconds-to-time (- beeminder-when-the-day-ends))))) 698 + 699 + (defun beeminder-human-time (time) 700 + "Convert (future) TIME to a human-friendly format. 701 + - For today, the time. 702 + - For tomorrow, the string `beeminder-tomorrow-code' (by default) and 703 + the time. 704 + - For times within a week, abbreviation of the weekday or a plus and 705 + a number of days (depending on `beeminder-human-time-use-weekday') 706 + and the time. 707 + - For later times, iso date without time. 708 + Midnight is treated as belonging to the previous day, not the following one." 709 + (let ((delta (- (beeminder-time-to-days time) 710 + (beeminder-time-to-days (beeminder-current-time))))) 711 + (cond ((zerop delta) (format-time-string " %R" time)) 712 + ((= 1 delta) (concat " " beeminder-tomorrow-code 713 + (format-time-string " %R" time))) 714 + ((<= delta 7) 715 + (concat (if beeminder-human-time-use-weekday 716 + (format-time-string " %a" 717 + (time-add time 718 + (seconds-to-time (- beeminder-when-the-day-ends)))) 719 + (format " +%d" delta)) 720 + " " 721 + (format-time-string "%R" time))) 722 + (t (format-time-string "%Y-%m-%d" 723 + (time-add time 724 + (seconds-to-time (- beeminder-when-the-day-ends)))))))) 725 + 726 + (defconst beeminder-lanes-to-faces-alist 727 + '((-2 . beeminder-red) (-1 . beeminder-yellow) (1 . beeminder-blue) (2 . beeminder-green)) 728 + "Alist mapping the (normalized) value of lane to goal colors.") 729 + 730 + (defun beeminder-normalize-lane (lane-number) 731 + "Normalize LANE-NUMBER into the interval -2 .. 2. 732 + This means to return 2 for LANE-NUMBER greater than 2 and -2 for 733 + LANE-NUMBER less than -2." 734 + (min (max lane-number -2) 2)) 735 + 736 + (defun beeminder-display-string-field (goal field &optional width invisible) 737 + "Return GOAL's FIELD (which should be a symbol) as a string. 738 + Optionally use length WIDTH (padded from the right with spaces). 739 + Make it invisible if INVISIBLE is non-nil." 740 + (let ((text (format (if width 741 + (format "%%-%d.%ds" width width) 742 + "%s") 743 + (cdr (assoc field goal))))) 744 + (if invisible 745 + (propertize text 'invisible invisible) 746 + text))) 747 + 748 + (defun beeminder-display-losedate-human (goal) 749 + "Return the losedate field of GOAL in human-friendly format." 750 + (beeminder-human-time (seconds-to-time (1+ (cdr (assoc 'losedate goal)))))) 751 + 752 + (defun beeminder-get-rate (goal) 753 + "Return the rate of GOAL." 754 + (elt (cdr (assoc 'mathishard goal)) 2)) 755 + 756 + (defun beeminder-display-rate (goal) 757 + "Return the rate of the GOAL (with units), as a string." 758 + (let ((rate (beeminder-get-rate goal))) 759 + (format (concat 760 + (number-to-human-string rate 4) 761 + "/%s") 762 + (cdr (assoc 'runits goal))))) 763 + 764 + (defun beeminder-display-pledge (goal) 765 + "Return the pledge of the GOAL, as a string." 766 + (format "$%.2f" (cdr (assoc 'pledge goal)))) 767 + 768 + (defcustom beeminder-goal-pp-format 769 + '((beeminder-display-string-field slug 12) 770 + " " 771 + beeminder-display-losedate-human 772 + " " 773 + (beeminder-display-string-field limsum 16) 774 + " " 775 + beeminder-display-rate 776 + " " 777 + beeminder-display-pledge 778 + " " 779 + (beeminder-display-string-field title)) 780 + "The format for displaying a Beeminder goal. 781 + It is a list whose elements are either strings, printed verbatim, 782 + either functions, which are then called with one argument (the 783 + goal), or lists, in which case the car of the list is a function 784 + and the cdr the list of arguments it should get after the goal." 785 + :type 'sexp 786 + :group 'beeminder) 787 + 788 + (defun beeminder-goal-face (goal) 789 + "Return the face for displaying GOAL." 790 + (if (beeminder-alist-get (intern (cdr (assoc 'slug goal))) 791 + beeminder-dirty-alist) 792 + 'beeminder-dirty 793 + (cdr (assoc (* (cdr (assoc 'yaw goal)) 794 + (beeminder-normalize-lane (cdr (assoc 'lane goal)))) 795 + beeminder-lanes-to-faces-alist)))) 796 + 797 + (defun beeminder-goal-representation (goal) 798 + "The string representation of GOAL, with the face applied." 799 + (propertize (mapconcat (lambda (field-specifier) 800 + (cond 801 + ((functionp field-specifier) (funcall field-specifier goal)) 802 + ((consp field-specifier) (apply (car field-specifier) 803 + goal 804 + (cdr field-specifier))) 805 + ((stringp field-specifier) field-specifier))) 806 + beeminder-goal-pp-format "") 807 + 'face 808 + (beeminder-goal-face goal))) 809 + 810 + (defun beeminder-display-first-goal () 811 + "Display the first goal in the echo area. 812 + Normally, this should be one of the goals with the nearest 813 + deadline. Caution: if more than one goal has the same deadline, 814 + it is not obvious which one is returned as the first from the 815 + server! You might want to bind this function globally so that 816 + you don't need to enter the Beeminder mode to see the nearest 817 + deadline." 818 + (interactive) 819 + (let* ((goal (car beeminder-goals)) 820 + (minutes (/ (- (cdr (assoc 'losedate goal)) 821 + (time-to-seconds (beeminder-current-time))) 822 + 60))) 823 + (beeminder-log (format "next goal: %s (%d minute%s left, %s to do)" 824 + (replace-regexp-in-string 825 + " \\{2,\\}" 826 + " " 827 + (beeminder-goal-representation goal)) 828 + minutes 829 + (beeminder-plural-ending minutes) 830 + (let ((limsum (cdr (assoc 'limsum goal)))) 831 + (string-match "[[:digit:]]+\\(\\.[[:digit:]]*\\)?" limsum) 832 + (match-string 0 limsum)))))) 833 + 834 + 835 + ;; Faces for goals 836 + 837 + (defface beeminder-green '((t :foreground "#080")) 838 + "Face for displaying Beeminder goals in green." 839 + :group 'beeminder-faces) 840 + 841 + (defface beeminder-blue '((t :foreground "#008")) 842 + "Face for displaying Beeminder goals in blue." 843 + :group 'beeminder-faces) 844 + 845 + (defface beeminder-yellow '((t :foreground "#880")) 846 + "Face for displaying Beeminder goals in green." 847 + :group 'beeminder-faces) 848 + 849 + (defface beeminder-red '((t :foreground "#800")) 850 + "Face for displaying Beeminder goals in red." 851 + :group 'beeminder-faces) 852 + 853 + 854 + ;; Beeminder EWOC 855 + 856 + (defvar beeminder-goals-ewoc nil) 857 + 858 + (defvar beeminder-short-header nil 859 + "If t, the default header is (extremely) shortened.") 860 + 861 + (defun beeminder-toggle-short-header (&optional arg) 862 + "Toggle shortening the header for Beeminder goal list. 863 + If ARG is positive, shorten the header; otherwise, do not." 864 + (interactive "P") 865 + (setq beeminder-short-header 866 + (if (null arg) 867 + (not beeminder-short-header) 868 + (> (prefix-numeric-value arg) 0))) 869 + (save-current-goal 870 + (ewoc-set-hf beeminder-goals-ewoc (beeminder-ewoc-header) "") 871 + (ewoc-refresh beeminder-goals-ewoc))) 872 + 873 + (define-key beeminder-mode-map (kbd "=") #'beeminder-toggle-short-header) 874 + 875 + (defun beeminder-print-filter (filter) 876 + "Return a printed representation of FILTER. 877 + It should be an element of `beeminder-current-filters'." 878 + (funcall (nth 3 (assoc (car filter) beeminder-filters)) (cdr filter))) 879 + 880 + (defun beeminder-ewoc-header () 881 + "Generate header for the Beeminder EWOC." 882 + (concat (format (if beeminder-short-header 883 + "Beeminder goals user:%s goals:%s/%d" 884 + "Beeminder goals for user %s (%s goals displayed out of %d total)") 885 + beeminder-username 886 + (if beeminder-goals-ewoc 887 + (length (ewoc-collect beeminder-goals-ewoc #'true)) 888 + 0) 889 + (length beeminder-goals)) 890 + (propertize (concat (format (if beeminder-short-header 891 + " srt:%s" 892 + "\nsorting criterion: %s") 893 + (caddr beeminder-current-sorting-setting)) 894 + (if beeminder-short-header 895 + (format " e%s" 896 + (if beeminder-show-everyday "+" "-")) 897 + (format " everyday goals: %s" 898 + (if beeminder-show-everyday 899 + "displayed" 900 + "omitted"))) 901 + (format (if beeminder-short-header 902 + " fil:%s" 903 + (format "\nfilter%s: %%s\n" 904 + (beeminder-plural-ending 905 + (length beeminder-current-filters)))) 906 + (if beeminder-current-filters 907 + (mapconcat #'beeminder-print-filter 908 + beeminder-current-filters 909 + ", ") 910 + "none"))) 911 + 'face 'shadow) 912 + (aif beeminder-notification (concat " " it) ""))) 913 + 914 + (defun beeminder-create-goals-ewoc () 915 + "Return a newly created EWOC for Beeminder goals." 916 + (ewoc-create (lambda (goal) (insert (beeminder-goal-representation goal))) 917 + (beeminder-ewoc-header))) 918 + 919 + (defun beeminder-populate-ewoc () 920 + "Populate Beeminder EWOC using the goal list. 921 + In particular, apply filtering and sorting settings. Note: since 922 + only the last sorting criterion is remembered, and sorting is 923 + stable, this might actually change the ordering of goals, which 924 + may have been sorted by another criterion previously." 925 + (ewoc-filter beeminder-goals-ewoc #'ignore) 926 + (mapcar (lambda (goal) 927 + (ewoc-enter-last beeminder-goals-ewoc goal)) 928 + beeminder-goals) 929 + (beeminder-apply-filters) 930 + (apply #'beeminder-sort-by-field beeminder-current-sorting-setting) 931 + (ewoc-set-hf beeminder-goals-ewoc (beeminder-ewoc-header) "") 932 + (ewoc-refresh beeminder-goals-ewoc) 933 + (with-current-buffer (ewoc-buffer beeminder-goals-ewoc) 934 + (goto-char (point-min)))) 935 + 936 + (defun beeminder-list-goals () 937 + "Switch to a buffer containing the list of Beeminder goals." 938 + (interactive) 939 + (aif (get-buffer "*Beeminder goals*") 940 + (switch-to-buffer it) 941 + (switch-to-buffer "*Beeminder goals*") 942 + (buffer-disable-undo) 943 + (beeminder-mode)) 944 + (let ((inhibit-read-only t)) 945 + (erase-buffer) 946 + (setq beeminder-goals-ewoc (beeminder-create-goals-ewoc)) 947 + (beeminder-populate-ewoc)) 948 + (setq truncate-lines t) 949 + (unless beeminder-goals 950 + (beeminder-get-goals))) 951 + 952 + 953 + ;; Current time function 954 + 955 + (defalias 'beeminder-current-time 'current-time 956 + "An alias for current-time, useful for testing/debugging.") 957 + 958 + 959 + ;; Sorting 960 + 961 + (defcustom beeminder-default-sorting-setting (list 'losedate #'< "losedate") 962 + "Default sorting setting for Beeminder goals. 963 + This is a list whose first element is the field according to 964 + which the sorting should be done, then the predicate, and then 965 + the printed representation of this sorting method (as a string)." 966 + :type 'sexp 967 + :group 'beeminder) 968 + 969 + (defvar beeminder-current-sorting-setting beeminder-default-sorting-setting) 970 + 971 + (defmacro save-current-goal (&rest body) 972 + "Evaluate BODY and bring the point back to the current goal. 973 + If the Beeminder EWOC disappeared (for some reason), just 974 + evaluate the body." 975 + (declare (indent 0) (debug t)) 976 + `(if beeminder-goals-ewoc 977 + (with-current-buffer (ewoc-buffer beeminder-goals-ewoc) 978 + (let* ((current-goal-slug 979 + (if (beeminder-before-first-goal-p) 980 + nil 981 + (beeminder-get-slug (ewoc-data (ewoc-locate beeminder-goals-ewoc))))) 982 + (current-line (unless current-goal-slug (line-number-at-pos)))) 983 + ,@body 984 + (cond ((not current-goal-slug) 985 + (goto-char (point-min)) 986 + (forward-line (1- current-line))) 987 + (t 988 + (ewoc-goto-node beeminder-goals-ewoc (ewoc-nth beeminder-goals-ewoc 0)) 989 + (let ((current-node (ewoc-nth beeminder-goals-ewoc 0))) 990 + (while (and current-node 991 + (not (eq (beeminder-get-slug (ewoc-data current-node)) 992 + current-goal-slug))) 993 + (ewoc-goto-next beeminder-goals-ewoc 1) 994 + (setq current-node (ewoc-next beeminder-goals-ewoc current-node))) 995 + (unless current-node (goto-char (point-min)))))))) 996 + ,@body)) 997 + 998 + (defun beeminder-sort-by-field (field predicate info) 999 + "Sort entries in `beeminder-goals-ewoc' by FIELD, using PREDICATE. 1000 + INFO is the printed representation of the sorting criterion." 1001 + (save-current-goal 1002 + (ewoc-sort beeminder-goals-ewoc (lambda (x y) 1003 + (funcall predicate 1004 + (cdr (assoc field x)) 1005 + (cdr (assoc field y))))) 1006 + (ewoc-refresh beeminder-goals-ewoc) 1007 + (setq beeminder-current-sorting-setting (list field predicate info)) 1008 + (ewoc-set-hf beeminder-goals-ewoc (beeminder-ewoc-header) ""))) 1009 + 1010 + (defun beeminder-sort-by-losedate () 1011 + "Sort entries in `beeminder-goals' by losedate." 1012 + (interactive) 1013 + (beeminder-sort-by-field 'losedate #'< "losedate")) 1014 + 1015 + (defun beeminder-seconds-to-from-midnight (time) 1016 + "Convert TIME to seconds from midnight. 1017 + If after 6:00, convert to seconds to midnight (with a minus 1018 + sign). The magic time constant 6:00 is the result of Beeminder's way 1019 + of dealing with the \"midnight\" setting." 1020 + (let* ((decoded-time (decode-time time)) 1021 + (seconds (+ (car decoded-time) 1022 + (* 60 (cadr decoded-time)) 1023 + (* 3600 (caddr decoded-time))))) 1024 + (if (> seconds (* 6 60 60)) 1025 + (- seconds (* 24 60 60)) 1026 + seconds))) 1027 + 1028 + (defun beeminder-earlier-midnight (sec1 sec2 time) 1029 + "Compare SEC1 and SEC2, taking into account the TIME. 1030 + All three parameters are expressed as seconds from midnight, like 1031 + the result of calling `beeminder-seconds-to-from-midnight'. If 1032 + SEC1 < SEC2 < TIME, return t. If TIME < SEC1 < SEC2, return t. 1033 + If SEC2 < TIME < SEC1, return t. In all other cases, return nil. 1034 + This function is useful for sorting goals by their \"midnight\" 1035 + setting, with the goals which are after their \"midnight\" at the 1036 + end." 1037 + (or (increasingp sec1 sec2 time) 1038 + (increasingp time sec1 sec2) 1039 + (increasingp sec2 time sec1))) 1040 + 1041 + (defun beeminder-sort-by-midnight () 1042 + "Sort entries in `beeminder-goals' by their midnight, taking current time into consideration." 1043 + (interactive) 1044 + (beeminder-sort-by-field 1045 + 'deadline 1046 + (lambda (x y) 1047 + (beeminder-earlier-midnight 1048 + x y (beeminder-seconds-to-from-midnight 1049 + (beeminder-current-time)))) 1050 + "midnight")) 1051 + 1052 + (define-key beeminder-mode-map "l" #'beeminder-sort-by-losedate) 1053 + (define-key beeminder-mode-map "m" #'beeminder-sort-by-midnight) 1054 + 1055 + 1056 + ;; Refreshing view and reloading goals 1057 + 1058 + (defun beeminder-refresh-goals-list () 1059 + "Refresh the goals list." 1060 + (interactive) 1061 + (save-current-goal 1062 + (beeminder-populate-ewoc))) 1063 + 1064 + (defvar beeminder-reloading-in-progress nil 1065 + "Non-nil if currently reloading data from the server.") 1066 + 1067 + (defun beeminder-clear-reloading-in-progress-flag () 1068 + "Clear the `beeminder-reloading-in-progress' flag. 1069 + Useful in case of an error." 1070 + (interactive) 1071 + (setq beeminder-reloading-in-progress nil)) 1072 + 1073 + (defun beeminder-reload-goals-list (&optional force) 1074 + "Reload the goals from the server. 1075 + With a prefix argument, do it even if reloading is in progress 1076 + \(this is useful when the `beeminder-reloading-in-progress' 1077 + variable is somehow messed up)." 1078 + (interactive "P") 1079 + (if (and beeminder-reloading-in-progress 1080 + (not force)) 1081 + (beeminder-log "fetching goals already in progress, please wait!") 1082 + (setq beeminder-reloading-in-progress t) 1083 + (beeminder-get-goals))) 1084 + 1085 + (define-key beeminder-mode-map (kbd "C-l") #'beeminder-refresh-goals-list) 1086 + (define-key beeminder-mode-map "g" #'beeminder-reload-goals-list) 1087 + 1088 + 1089 + ;; Filtering goals 1090 + 1091 + (defvar beeminder-current-filters '() 1092 + "Alist of filters currently in effect.") 1093 + 1094 + (defcustom beeminder-saved-filters '() 1095 + "A remembered set of filters for fast retrieval.") 1096 + 1097 + (defun beeminder-save-filters () 1098 + "Save the current filters." 1099 + (interactive) 1100 + (setq beeminder-saved-filters 1101 + (copy-alist beeminder-current-filters)) 1102 + (beeminder-log (format "current filter settings %s saved." beeminder-current-filters))) 1103 + 1104 + (defun beeminder-retrieve-filters () 1105 + "Retrieve saved filters." 1106 + (interactive) 1107 + (setq beeminder-current-filters 1108 + (copy-alist beeminder-saved-filters)) 1109 + (beeminder-refresh-goals-list) 1110 + (beeminder-log (format "filter settings %s retrieved." beeminder-current-filters))) 1111 + 1112 + (defun beeminder-clear-filters () 1113 + "Clear all filters. 1114 + If there are no saved filters, first save the current filters." 1115 + (interactive) 1116 + (unless beeminder-saved-filters 1117 + (beeminder-save-filters)) 1118 + (setq beeminder-current-filters '()) 1119 + (beeminder-refresh-goals-list)) 1120 + 1121 + (define-key beeminder-mode-map "c" #'beeminder-clear-filters) 1122 + 1123 + (define-prefix-command 'beeminder-filter-map) 1124 + (define-key beeminder-mode-map "f" #'beeminder-filter-map) 1125 + (define-key beeminder-filter-map "c" #'beeminder-clear-filters) 1126 + (define-key beeminder-filter-map "s" #'beeminder-save-filters) 1127 + (define-key beeminder-filter-map "f" #'beeminder-retrieve-filters) 1128 + (define-key beeminder-filter-map "r" #'beeminder-retrieve-filters) 1129 + 1130 + (defcustom beeminder-default-filter-days 3 1131 + "Defalt number of days used for filtering by losedate. 1132 + If the user doesn't specify the number of days for filtering, all 1133 + goals with more than this amount of days left to losedate will be 1134 + filtered out." 1135 + :type 'integer 1136 + :group 'beeminder) 1137 + 1138 + (defcustom beeminder-use-goal-midnight-today-values nil 1139 + "If non-nil, compute today's values using the goal's midnight. 1140 + If nil, use the global midnight defined by 1141 + `beeminder-when-the-day-ends'." 1142 + :type 'boolean 1143 + :group 'beeminder) 1144 + 1145 + (defcustom beeminder-default-filter-donetoday 100 1146 + "Default percentage of donetoday used for filtering." 1147 + :type 'integer 1148 + :group 'beeminder) 1149 + 1150 + (defcustom beeminder-default-filter-urgent-hours 8 1151 + "Default time (in hours) to deadline to consider a goal urgent." 1152 + :type 'integer 1153 + :group 'beeminder) 1154 + 1155 + (defcustom beeminder-show-dirty-donetoday t 1156 + "If non-nil, show dirty goals even if they would be normally 1157 + filtered out by the \"donetoday\" filter." 1158 + :type 'boolean 1159 + :group 'beeminder) 1160 + 1161 + (defcustom beeminder-show-everyday t 1162 + "If non-nil, show \"everyday goals\" irrespective of the 1163 + \"days\" filter.") 1164 + 1165 + (defcustom beeminder-everyday-goals-list 1166 + '() 1167 + "A list of slugs of \"everyday goals\". These are the goals which 1168 + should be done every day, so even when filtering goals with deadline 1169 + after some number of days, they should be shown.") 1170 + 1171 + (defun beeminder-toggle-show-everyday (arg) 1172 + "Toggle showing \"everyday goals\" if ARG is zero or nil. 1173 + If ARG is positive, turn it on; if negative, off." 1174 + (interactive "P") 1175 + (let ((narg (prefix-numeric-value arg))) 1176 + (cond ((null arg) 1177 + (setq beeminder-show-everyday (not beeminder-show-everyday))) 1178 + ((> narg 0) 1179 + (setq beeminder-show-everyday t)) 1180 + ((< narg 0) 1181 + (setq beeminder-show-everyday nil)))) 1182 + (beeminder-refresh-goals-list)) 1183 + 1184 + (define-key beeminder-mode-map "e" #'beeminder-toggle-show-everyday) 1185 + (define-key beeminder-filter-map "e" #'beeminder-toggle-show-everyday) 1186 + 1187 + (defun beeminder-days-p (goal days) 1188 + "Return nil if time to derailment of GOAL > DAYS. 1189 + If DAYS is negative, return nil if time to derailment of GOAL is 1190 + <= -DAYS. If the goal is in `beeminder-everyday-goals-list', 1191 + return t anyway." 1192 + (if (and beeminder-show-everyday 1193 + (memq (beeminder-get-slug goal) beeminder-everyday-goals-list)) 1194 + t 1195 + (let ((days-left (- (beeminder-time-to-days (cdr (assoc 'losedate goal))) 1196 + (beeminder-time-to-days (beeminder-current-time))))) 1197 + (if (>= days 0) 1198 + (<= days-left days) 1199 + (>= days-left (- days)))))) 1200 + 1201 + (defun beeminder-donetoday-p (goal percentage) 1202 + "Return nil if donetoday for GOAL >= PERCENTAGE * day's amount. 1203 + If PERCENTAGE is negative, return nil if donetoday of GOAL is 1204 + less than PERCENTAGE * day's amount. Take the variable 1205 + `beeminder-show-dirty-donetoday' into account." 1206 + (if (and beeminder-show-dirty-donetoday 1207 + (beeminder-alist-get (beeminder-get-slug goal) beeminder-dirty-alist)) 1208 + t 1209 + (let* ((rate (beeminder-get-rate goal)) 1210 + (daily-rate (/ rate 1211 + (cl-case (intern (cdr (assoc 'runits goal))) 1212 + (y 365.0) 1213 + (m (/ 365.0 12)) 1214 + (w 7.0) 1215 + (d 1.0) 1216 + (h (/ 1 24.0))))) 1217 + (100*donetoday (* 100 (cdr (assoc 'donetoday goal)))) 1218 + (percentage*daily-rate (* percentage daily-rate))) 1219 + (when (> rate 0) 1220 + (cond ((> percentage 0) 1221 + (< 100*donetoday 1222 + percentage*daily-rate)) 1223 + ((zerop percentage) 1224 + (zerop 100*donetoday)) 1225 + (t 1226 + (>= 100*donetoday (- percentage*daily-rate)))))))) 1227 + 1228 + (defun beeminder-calculate-midnight-offset (seconds) 1229 + "Add (* 24 60 60) to SECONDS if negative." 1230 + (if (> seconds 0) 1231 + seconds 1232 + (+ (* 24 60 60) seconds))) 1233 + 1234 + (defun beeminder-urgent-p (goal hours) 1235 + "Return nil if time to deadline for GOAL is > HOURS. 1236 + If HOURS is negative or zero, return nil if time to deadline is 1237 + <= -HOURS." 1238 + (let* ((deadline (beeminder-calculate-midnight-offset (beeminder-alist-get 'deadline goal))) 1239 + (now (decode-time (beeminder-current-time))) 1240 + (now-sec (car now)) 1241 + (now-min (cadr now)) 1242 + (now-hour (caddr now)) 1243 + (now-time (+ now-sec (* 60 now-min) (* 3600 now-hour))) 1244 + (time-to-deadline (beeminder-calculate-midnight-offset (- deadline now-time)))) 1245 + (if (> hours 0) 1246 + (<= time-to-deadline (* 3600 hours)) 1247 + (> time-to-deadline (* -3600 hours))))) 1248 + 1249 + (defun beeminder-not-killed-p (goal kill-list) 1250 + "Return nil if GOAL is in the KILL-LIST." 1251 + (not (member (beeminder-get-slug goal) kill-list))) 1252 + 1253 + (defvar beeminder-filters `((losedate ,#'beeminder-days-p 1254 + ,beeminder-default-filter-days 1255 + (lambda (days) 1256 + (format (if beeminder-short-header 1257 + "d2d(%s%d)" 1258 + "days to derailment (%s%d)") 1259 + (if (>= days 0) "<=" ">=") 1260 + (abs days)))) 1261 + (donetoday ,#'beeminder-donetoday-p 1262 + ,beeminder-default-filter-donetoday 1263 + (lambda (donetoday) 1264 + (format (if beeminder-short-header 1265 + "dt(%s%d%%)" 1266 + "done today (%s%d%%)") 1267 + (cond ((> donetoday 0) "<") 1268 + ((zerop donetoday) "=") 1269 + (t ">=")) 1270 + (abs donetoday)))) 1271 + (urgent ,#'beeminder-urgent-p 1272 + ,beeminder-default-filter-urgent-hours 1273 + (lambda (hours) 1274 + (format (if beeminder-short-header 1275 + "u(%s%dh)" 1276 + "urgent (%s%d hours to deadline)") 1277 + (if (> hours 0) "<=" ">") 1278 + (abs hours)))) 1279 + (killed ,#'beeminder-not-killed-p 1280 + '() 1281 + (lambda (kill-list) 1282 + (format (if beeminder-short-header 1283 + "%dgk" 1284 + "%d goal%s killed") 1285 + (length kill-list) 1286 + (beeminder-plural-ending (length kill-list)))))) 1287 + 1288 + "List of possible filters. Each element is a list, consisting of: 1289 + - symbol, denoting the filter, 1290 + - predicate (with two arguments - the goal and the parameter), 1291 + - default value for the parameter, 1292 + - formatting function (with one argument - the parameter).") 1293 + 1294 + (defun beeminder-kill-goal (gnode) 1295 + "Delete GNODE from `beeminder-goals-ewoc'." 1296 + (interactive (list (beeminder-slug-to-gnode (intern (cdr (assoc 'slug (current-or-read-goal))))))) 1297 + (if gnode 1298 + (let ((inhibit-read-only t) 1299 + (next-goal (or (ewoc-next beeminder-goals-ewoc gnode) 1300 + (ewoc-prev beeminder-goals-ewoc gnode)))) 1301 + (ewoc-delete beeminder-goals-ewoc gnode) 1302 + (ewoc-refresh beeminder-goals-ewoc) 1303 + (beeminder-set-alist-value 'killed 1304 + 'beeminder-current-filters 1305 + (cons (beeminder-get-slug (ewoc-data gnode)) 1306 + (beeminder-alist-get 'killed beeminder-current-filters))) 1307 + (ewoc-set-hf beeminder-goals-ewoc (beeminder-ewoc-header) "") 1308 + (if next-goal 1309 + (ewoc-goto-node beeminder-goals-ewoc next-goal) 1310 + (goto-char (point-min))) 1311 + (beeminder-log (format "goal %s killed (hidden from view)." (cdr (assoc 'slug (ewoc-data gnode)))))) 1312 + (beeminder-log (format "goal %s already killed." (cdr (assoc 'slug (ewoc-data gnode))))))) 1313 + 1314 + (define-key beeminder-mode-map (kbd "C-k") #'beeminder-kill-goal) 1315 + (define-key beeminder-filter-map "k" #'beeminder-kill-goal) 1316 + 1317 + (defun beeminder-show-kills () 1318 + "Show all killed goals." 1319 + (interactive) 1320 + (beeminder-log (format "killed goals: %s." 1321 + (aif (beeminder-alist-get 'killed beeminder-current-filters) 1322 + (mapconcat #'symbol-name it ", ") 1323 + "none")))) 1324 + 1325 + (defun beeminder-clear-kills () 1326 + "Unkill all killed goals." 1327 + (interactive) 1328 + (setq beeminder-current-filters 1329 + (assq-delete-all 'killed beeminder-current-filters)) 1330 + (beeminder-refresh-goals-list)) 1331 + 1332 + (defun beeminder-clear-or-show-kills (arg) 1333 + "Unkill all killed goals if ARG is nil. 1334 + With prefix argument, show the list of killed goals." 1335 + (interactive "P") 1336 + (if arg 1337 + (beeminder-show-kills) 1338 + (beeminder-clear-kills))) 1339 + 1340 + (define-key beeminder-mode-map (kbd "C-y") #'beeminder-clear-or-show-kills) 1341 + (define-key beeminder-filter-map "y" #'beeminder-clear-or-show-kills) 1342 + 1343 + (defun beeminder-apply-filter (filter) 1344 + "Apply FILTER (a dotted pair of symbol and parameter). 1345 + This means deleting some goals from `beeminder-goals-ewoc'." 1346 + (save-current-goal 1347 + (ewoc-filter beeminder-goals-ewoc 1348 + (lambda (goal) 1349 + (funcall (cadr (assoc (car filter) beeminder-filters)) 1350 + goal (cdr filter)))))) 1351 + 1352 + (defun beeminder-apply-filters () 1353 + "Apply filters from `beeminder-current-filters' in sequence." 1354 + (mapc #'beeminder-apply-filter beeminder-current-filters)) 1355 + 1356 + (defun beeminder-enable-filter (filter parameter) 1357 + "Enable FILTER (symbol) with PARAMETER (number). 1358 + Disable FILTER if PARAMETER is nil." 1359 + (beeminder-set-alist-value filter 'beeminder-current-filters parameter) 1360 + (setq beeminder-current-filters (rassq-delete-all nil beeminder-current-filters)) 1361 + (beeminder-refresh-goals-list)) 1362 + 1363 + (defun beeminder-filter-parameter (raw-prefix default) 1364 + "Return filter parameter based on RAW-PREFIX and DEFAULT." 1365 + (cond ((eq raw-prefix '-) nil) 1366 + ((null raw-prefix) default) 1367 + (t (prefix-numeric-value raw-prefix)))) 1368 + 1369 + (defun beeminder-filter-by-losedate (&optional days) 1370 + "Filter out goals with time to losedate greater than DAYS." 1371 + (interactive "P") 1372 + (beeminder-enable-filter 'losedate 1373 + (beeminder-filter-parameter days 1374 + beeminder-default-filter-days))) 1375 + 1376 + (defun beeminder-filter-by-donetoday (&optional percentage) 1377 + "Filter out goals with donetoday greater than PERCENTAGE." 1378 + (interactive "P") 1379 + (beeminder-enable-filter 'donetoday 1380 + (beeminder-filter-parameter percentage 1381 + beeminder-default-filter-donetoday))) 1382 + 1383 + (defun beeminder-filter-by-urgent (&optional hours) 1384 + "Filter out goals with time to deadline greater than HOURS." 1385 + (interactive "P") 1386 + (beeminder-enable-filter 'urgent 1387 + (beeminder-filter-parameter hours 1388 + beeminder-default-filter-urgent-hours))) 1389 + 1390 + (define-key beeminder-mode-map (kbd "d") #'beeminder-filter-by-losedate) 1391 + (define-key beeminder-filter-map (kbd "d") #'beeminder-filter-by-losedate) 1392 + (define-key beeminder-mode-map (kbd "t") #'beeminder-filter-by-donetoday) 1393 + (define-key beeminder-filter-map (kbd "t") #'beeminder-filter-by-donetoday) 1394 + (define-key beeminder-mode-map (kbd "u") #'beeminder-filter-by-urgent) 1395 + (define-key beeminder-filter-map (kbd "u") #'beeminder-filter-by-urgent) 1396 + 1397 + 1398 + ;; Displaying goal details 1399 + 1400 + (defcustom beeminder-goal-template-fields-alist 1401 + '((slug . (propertize (symbol-name (beeminder-get-slug goal)) 'face (beeminder-goal-face goal))) 1402 + (limsum . (propertize (cdr (assoc 'limsum goal)) 'face (beeminder-goal-face goal))) 1403 + (backburnerp . (if (string= (cdr (assoc 'burner goal)) "backburner") "(backburner)" "")) 1404 + (username . beeminder-username) 1405 + (dirtyp . (if (assoc (beeminder-get-slug goal) beeminder-dirty-alist) 1406 + (propertize " (goal dirty!)" 'face 'beeminder-dirty) "")) 1407 + (target . (highlight-subtly (number-to-string (elt (cdr (assoc 'mathishard goal)) 1)))) 1408 + (goaldate . (highlight-subtly (format-time-string "%x" (seconds-to-time (elt (cdr (assoc 'mathishard goal)) 0))))) 1409 + (rate . (highlight-subtly (number-to-human-string (beeminder-get-rate goal)))) 1410 + (runit . (highlight-subtly 1411 + (cl-case (intern (cdr (assoc 'runits goal))) 1412 + (d "day") 1413 + (w "week") 1414 + (m "month") 1415 + (h "hour") 1416 + (y "year")))) 1417 + (curval . (highlight-subtly (number-to-human-string (cdr (assoc 'curval goal))))) 1418 + (autodatap . (aif (cdr (assoc 'autodata goal)) 1419 + (concat ", autodata source: " 1420 + (highlight-subtly it)) 1421 + "")) 1422 + (goaltype . (highlight-subtly (beeminder-display-goal-type (cdr (assoc 'goal_type goal))))) 1423 + (losedate . (highlight-subtly (trim-leading-whitespace 1424 + (beeminder-display-losedate-human goal)))) 1425 + (pledge . (highlight-subtly (beeminder-display-pledge goal))) 1426 + (midnight . (highlight-subtly (beeminder-display-midnight-setting (cdr (assoc 'deadline goal))))) 1427 + (donetoday . (highlight-subtly (number-to-human-string (cdr (assoc 'donetoday goal))))) 1428 + (datapoints . (propertize (beeminder-format-datapoints goal) 'face 1429 + 'shadow)) 1430 + (history-length . (highlight-subtly (let ((hl (cdr (assoc 'history-length goal)))) 1431 + (if (zerop hl) "all" (format "%s" hl)))))) 1432 + "Alist of symbols and corresponding pieces of code to evaluate 1433 + and insert the result in the goal details info.") 1434 + 1435 + (defun beeminder-display-time-field (alist field) 1436 + "Return ALIST's (unix-time) FIELD formatted." 1437 + (format-time-string "%x %X" (seconds-to-time (cdr (assoc field alist))))) 1438 + 1439 + (defcustom beeminder-datapoint-format 1440 + '((beeminder-display-string-field id 25 t) 1441 + (beeminder-display-time-field timestamp) 1442 + " " 1443 + (beeminder-display-string-field value 8) 1444 + " " 1445 + (beeminder-display-string-field comment)) 1446 + "The format for displaying a goal's datapoint. 1447 + The format is identical to that of `beeminder-goal-pp-format'.") 1448 + 1449 + (defun beeminder-datapoint-representation (datapoint) 1450 + "The string representation of DATAPOINT." 1451 + ;; TODO: factor out common code of this and `beeminder-goal-pp-format'. 1452 + (mapconcat (lambda (field-specifier) 1453 + (cond 1454 + ((functionp field-specifier) (funcall field-specifier datapoint)) 1455 + ((consp field-specifier) (apply (car field-specifier) 1456 + datapoint 1457 + (cdr field-specifier))) 1458 + ((stringp field-specifier) field-specifier))) 1459 + beeminder-datapoint-format "")) 1460 + 1461 + (defun beeminder-format-datapoints (goal) 1462 + "Return the printed representation of GOAL's datapoints." 1463 + (mapconcat #'beeminder-datapoint-representation 1464 + (reverse (cdr (assoc 'datapoints goal))) 1465 + "\n")) 1466 + 1467 + (defun beeminder-insert-goal-template-with-expansion (template goal) 1468 + "Insert TEMPLATE with information about GOAL. 1469 + If a substring of the form \"#SYMBOL\" is found, and SYMBOL is 1470 + a key in the `beeminder-goal-template-fields-alist' variable, 1471 + \"#SYMBOL\" is replaced with result of evaluating the associated 1472 + value. If there is no such entry, the SYMBOL is looked up in the 1473 + alist representing the current goal, and \"#SYMBOL\" is replaced 1474 + with its printed representation (using `format''s \"%s\" 1475 + specifier). In the latter case, the result is colorized with the 1476 + `subtle-highlight-face'; in the former case, code in 1477 + `beeminder-goal-template-fields-alist' should take care of 1478 + colorization if needed. 1479 + 1480 + If a substring of the form \"#SEXP\" is found, and SEXP is not 1481 + a symbol, \"#SEXP\" is replaced with the result of evaluating SEXP. 1482 + Within SEXP, the variable `goal' is bound to the alist holding the 1483 + current's goal properties. 1484 + 1485 + Should someone want to insert a literal \"#\" character, the form 1486 + \"#(identity \"#\")\" can be used. 1487 + 1488 + Warning: this function uses `eval', so evil code in TEMPLATE or 1489 + `beeminder-goal-template-fields-alist' can do real harm!" 1490 + (save-excursion (insert template)) 1491 + (while (search-forward "#" nil t) 1492 + (let ((begin (1- (point))) 1493 + (sexp (read (current-buffer)))) 1494 + (delete-region begin (point)) 1495 + (insert (format "%s" 1496 + (cond ((symbolp sexp) 1497 + (aif (assoc sexp beeminder-goal-template-fields-alist) 1498 + (eval (cdr it) `((goal . ,goal) t)) 1499 + (highlight-subtly (format "%s" (cdr (assoc sexp goal)))))) 1500 + (t (eval sexp)))))))) 1501 + 1502 + (define-derived-mode beeminder-goal-mode special-mode "Beeminder goal" 1503 + "A major mode for a buffer displaying details of a Beeminder goal, 1504 + in particular the history of datapoints.") 1505 + 1506 + (defun beeminder-next-datapoint (count) 1507 + "Move forward COUNT datapoints." 1508 + (interactive "p") 1509 + (forward-line 1) 1510 + (re-search-forward "^[0-9a-f]\\{24\\}" nil t count) 1511 + (beginning-of-line)) 1512 + 1513 + (defun beeminder-previous-datapoint (count) 1514 + "Move forward COUNT datapoints." 1515 + (interactive "p") 1516 + (beginning-of-line) 1517 + (re-search-backward "^[0-9a-f]\\{24\\}" nil t count)) 1518 + 1519 + (define-key beeminder-goal-mode-map (kbd "n") #'beeminder-next-datapoint) 1520 + (define-key beeminder-goal-mode-map (kbd "p") #'beeminder-previous-datapoint) 1521 + 1522 + (defface subtle-highlight '((t :foreground "#004400")) 1523 + "Face for subtly highlighting things.") 1524 + 1525 + (defun highlight-subtly (string) 1526 + "Make STRING stand out, but only a little." 1527 + (propertize string 'face 'subtle-highlight)) 1528 + 1529 + (defun number-to-human-string (number &optional width) 1530 + "Convert NUMBER to a human-friendly form, at least WIDTH characters. 1531 + If NUMBER is greater than 10, use one decimal place. Otherwise, 1532 + use two. Trim any non-significant trailing zeros and the decimal 1533 + point if needed." 1534 + (let ((str (replace-regexp-in-string 1535 + "\\.?0+$" "" 1536 + (format (cond 1537 + ((> number 10) "%.1f") 1538 + (t "%.2f")) 1539 + number)))) 1540 + (if width (format (format "%%%ds" width) str) str))) 1541 + 1542 + (defun beeminder-display-midnight-setting (seconds) 1543 + "Convert SECONDS to or from midnight to a time string." 1544 + (when (< seconds 0) (setq seconds (+ seconds (* 24 60 60)))) 1545 + (let* ((hours (/ seconds 60 60)) 1546 + (minutes (/ (- seconds (* hours 60 60)) 60))) 1547 + (format "%d:%02d" hours minutes))) 1548 + 1549 + (defun beeminder-display-goal-type (goaltype) 1550 + "Convert GOALTYPE to a printed representation." 1551 + (cl-case (intern goaltype) 1552 + (hustler "do more") 1553 + (biker "odometer") 1554 + (fatloser "weight loss") 1555 + (gainer "gain weight") 1556 + (inboxer "inbox fewer") 1557 + (drinker "do less") 1558 + (custom "custom"))) 1559 + 1560 + (defcustom beeminder-goal-template 1561 + "Details for Beeminder goal #slug for user #username#backburnerp 1562 + #title#dirtyp 1563 + goal target: #target on #goaldate at rate #rate per #runit (currently at #curval, done today: #donetoday) 1564 + goal type: #goaltype#autodatap 1565 + safe until #losedate (current pledge: #pledge, left to do: #limsum, midnight setting: #midnight) 1566 + 1567 + Recent datapoints (#history-length days): 1568 + #datapoints 1569 + " 1570 + "The default template for displaying goal details. 1571 + See the docstring of the function 1572 + `beeminder-insert-goal-template-with-expansion' for the list of 1573 + available keywords.") 1574 + 1575 + (defun beeminder-refresh-goal-details () 1576 + "Refresh goal details, assuming that the respective buffer 1577 + exists and is set up properly." 1578 + (let ((inhibit-read-only t)) 1579 + (erase-buffer) 1580 + (beeminder-insert-goal-template-with-expansion 1581 + beeminder-goal-template 1582 + beeminder-detailed-goal)) 1583 + (goto-char (point-min))) 1584 + 1585 + (defvar beeminder-detailed-goal nil 1586 + "The current goal in the details buffer.") 1587 + 1588 + (defun beeminder-display-goal-details (goal) 1589 + "Display details about GOAL in a temporary buffer." 1590 + (interactive (list (current-or-read-goal))) 1591 + (pop-to-buffer "*Beeminder goal details*") 1592 + (remove-images (point-min) (point-max)) 1593 + (beeminder-goal-mode) 1594 + (setq-local beeminder-detailed-goal goal) 1595 + (beeminder-refresh-goal-details)) 1596 + 1597 + (define-key beeminder-mode-map (kbd "TAB") #'beeminder-display-goal-details) 1598 + 1599 + (defcustom beeminder-confirm-datapoint-deletion #'y-or-n-p 1600 + "How to ask for confirmation of datapoint deletion. 1601 + If nil, don't ask." 1602 + :type '(choice (const :tag "Ask with yes-or-no-p" yes-or-no-p) 1603 + (const :tag "Ask with y-or-n-p" y-or-n-p) 1604 + (const :tag "Don't ask at all" nil) 1605 + (funtion :tag "Predicate function")) 1606 + :group 'beeminder) 1607 + 1608 + (defun beeminder-get-datapoint-id () 1609 + "Return the id of the datapoint at point." 1610 + (save-excursion 1611 + (beginning-of-line) 1612 + (if (looking-at "[0-9a-f]\\{24\\}") 1613 + (match-string-no-properties 0) 1614 + (error "Not at a datapoint")))) 1615 + 1616 + (defun beeminder-delete-datapoint (id) 1617 + "Delete datapoint with id ID. 1618 + If called interactively, take the id from the beginning of the 1619 + line." 1620 + (interactive (list (beeminder-get-datapoint-id))) 1621 + (if (and beeminder-confirm-datapoint-deletion 1622 + (funcall beeminder-confirm-datapoint-deletion "Are you sure you want to delete this datapoint?")) 1623 + (beeminder-request-delete 1624 + (concat "/goals/" (cdr (assoc 'slug beeminder-detailed-goal)) "/datapoints/" id ".json") 1625 + (cl-function (lambda (&rest _) 1626 + (let ((datapoints (cdr (assoc 'datapoints beeminder-detailed-goal)))) 1627 + (beeminder-inc-alist-value 'donetoday 1628 + beeminder-detailed-goal 1629 + (- (cdr (assoc 'value (cl-find id datapoints 1630 + :key (lambda (dp) 1631 + (cdr (assoc 'id dp))) 1632 + :test #'string=))))) 1633 + (cl-delete id datapoints :key (lambda (dp) (cdr (assoc 'id dp))) :test #'string=) 1634 + (beeminder-make-goal-dirty (beeminder-get-slug beeminder-detailed-goal)) 1635 + (beeminder-refresh-goal-details) 1636 + (beeminder-log (format "datapoint %s succesfully deleted" id))))) 1637 + (cl-function (lambda (&key error-thrown &allow-other-keys) 1638 + (beeminder-log (format "error while deleting datapoint %s for goal %s: %s" 1639 + id 1640 + (cdr (assoc 'slug beeminder-detailed-goal)) 1641 + error-thrown) 1642 + :error)))))) 1643 + 1644 + (define-key beeminder-goal-mode-map (kbd "d") #'beeminder-delete-datapoint) 1645 + 1646 + (defun beeminder-get-datapoint (id datapoints) 1647 + "Return datapoint with id ID from DATAPOINTS." 1648 + (cl-find id datapoints 1649 + :key (lambda (dp) 1650 + (cdr (assoc 'id dp))) 1651 + :test #'string=)) 1652 + 1653 + (defun beeminder-edit-datapoint (id) 1654 + "Edit datapoint with id ID. 1655 + If called interactively, take the id from the beginning of the 1656 + line." 1657 + (interactive (list (beeminder-get-datapoint-id))) 1658 + (let* ((datapoints (reverse (cdr (assoc 'datapoints beeminder-detailed-goal)))) 1659 + (datapoint (aif (beeminder-get-datapoint id datapoints) 1660 + it 1661 + (error "%s" "Invalid datapoint id -- beeminder-get-datapoint"))) 1662 + (timestamp (ask-for-timestamp (cdr (assoc 'timestamp datapoint)))) 1663 + (value (string-to-number 1664 + (let ((default-value (cdr (assoc 'value datapoint)))) 1665 + (read-string (format "Value (default %s): " default-value) 1666 + nil nil (number-to-string default-value))))) 1667 + (comment (let ((comment-history 1668 + (mapcar (lambda (dp) 1669 + (cdr (assoc 'comment dp))) 1670 + datapoints))) 1671 + (read-string "Comment: " 1672 + (cdr (assoc 'comment datapoint)) 1673 + (cons 'comment-history 1674 + (1+ (position 1675 + id 1676 + datapoints 1677 + :key (lambda (dp) 1678 + (cdr (assoc 'id dp))) 1679 + :test #'string=))) 1680 + nil t)))) 1681 + (beeminder-log "updating datapoint...") 1682 + (beeminder-request-put (format "/goals/%s/datapoints/%s.json" 1683 + (beeminder-get-slug beeminder-detailed-goal) 1684 + id) 1685 + (list 1686 + (cons "value" (format "%s" value)) 1687 + (cons "comment" comment) 1688 + (cons "timestamp" (format "%s" timestamp))) 1689 + (cl-function (lambda (&rest _) (beeminder-log "updating datapoint...done"))) 1690 + (cl-function (lambda (&rest _) (beeminder-log "updating datapoint failed!" :error)))))) 1691 + 1692 + (define-key beeminder-goal-mode-map (kbd "e") #'beeminder-edit-datapoint) 1693 + 1694 + (defun beeminder-display-raw-goal-details () 1695 + "Display the raw details about GOAL in a temporary buffer. 1696 + The internal representation is an alist." 1697 + (interactive) 1698 + (let ((goal beeminder-detailed-goal)) 1699 + (pop-to-buffer "*Beeminder raw goal details*") 1700 + (let ((inhibit-read-only t)) 1701 + (erase-buffer) 1702 + (insert (pp-to-string goal)) 1703 + (goto-char (point-min)) 1704 + (special-mode)))) 1705 + 1706 + (define-key beeminder-goal-mode-map (kbd ".") #'beeminder-display-raw-goal-details) 1707 + 1708 + (defun beeminder-view-in-browser (goal) 1709 + "View GOAL in the web browser." 1710 + (interactive (list (or beeminder-detailed-goal (current-or-read-goal)))) 1711 + (browse-url (format "https://beeminder.com/%s/%s" beeminder-username (beeminder-alist-get 'slug goal)))) 1712 + 1713 + (define-key beeminder-mode-map (kbd "W") #'beeminder-view-in-browser) 1714 + (define-key beeminder-goal-mode-map (kbd "W") #'beeminder-view-in-browser) 1715 + 1716 + 1717 + ;; Downloading more datapoints 1718 + (defun beeminder-download-datapoints (slug-str days) 1719 + "Download datapoints for goal named SLUG-STR from last DAYS. 1720 + If called interactively in the *Beeminder goal details* buffer, use 1721 + current goal; otherwise, ask for the goal. If called without a prefix 1722 + argument, increase the downloaded history by 1723 + `beeminder-history-length' days." 1724 + (interactive (list (if beeminder-detailed-goal 1725 + (cdr (assoc 'slug beeminder-detailed-goal)) 1726 + (cdr (assoc 'slug (current-or-read-goal)))) 1727 + current-prefix-arg)) 1728 + (setq days 1729 + (if days 1730 + (prefix-numeric-value days) 1731 + beeminder-history-length)) 1732 + (setq days 1733 + (cond ((> days 0) 1734 + (+ (cdr (assoc 'history-length (beeminder-slug-to-goal (intern slug-str)))) 1735 + days)) 1736 + ((< days 0) 1737 + (- days)) 1738 + (t 0))) 1739 + (beeminder-log (format "fetching datapoints for goal %s..." slug-str)) 1740 + (beeminder-request-get (format "/goals/%s.json" slug-str) 1741 + (cons (cons "datapoints" "true") 1742 + (unless (zerop days) 1743 + (cons (cons "diff_since" 1744 + (number-to-string 1745 + (- (last-user-midnight (beeminder-current-time)) 1746 + (* days 24 60 60)))) 1747 + nil))) 1748 + (cl-function (lambda (&key data &allow-other-keys) 1749 + (beeminder-log (format "fetching datapoints for goal %s...done" slug-str)) 1750 + (let* ((gl (beeminder-slug-to-goal (intern slug-str))) 1751 + (dp (assoc 'datapoints gl)) 1752 + (hl (assoc 'history-length gl))) 1753 + (setcdr dp (beeminder-to-list (cdr (assoc 'datapoints data)))) 1754 + (setcdr hl days) 1755 + (when beeminder-detailed-goal 1756 + (beeminder-refresh-goal-details))))) 1757 + (cl-function (lambda (&key error-thrown &allow-other-keys) 1758 + (beeminder-log (format "fetching datapoints for goal %s...error: %s" slug-str error-thrown)))))) 1759 + 1760 + (define-key beeminder-goal-mode-map (kbd "m") #'beeminder-download-datapoints) 1761 + 1762 + 1763 + ;; Statistics 1764 + (defun beeminder-determine-date (time day-end) 1765 + "Return date for TIME, taking DAY-END into account. 1766 + TIME is the number of seconds counted from the beginning of Unix 1767 + epoch; DAY-END is the offset from midnight in seconds. The date 1768 + is a string in ISO 8601 basic format (i.e., \"20160417\" for 1769 + April 17, 2016)." 1770 + (format-time-string "%Y%m%d" (time-subtract time day-end))) 1771 + 1772 + (defun beeminder-gather-datapoints-by-day (goal) 1773 + "Return an alist of datapoints, collated by date. 1774 + The car of each entry is a string representing the date in ISO 1775 + 8601 basic format (i.e., \"20160417\" for April 17, 2016), and 1776 + the cdr is the list of datapoints. If 1777 + `beeminder-use-goal-midnight-today-values' is nil, use the goal's 1778 + \"midnight\" setting to determine the date; otherwise, use 1779 + `beeminder-when-the-day-ends'." 1780 + (let ((day-end (if beeminder-use-goal-midnight-today-values 1781 + beeminder-when-the-day-ends 1782 + (cdr (assoc 'deadline goal)))) 1783 + datapoints-by-day) 1784 + (mapc (lambda (datapoint) 1785 + (let ((date (beeminder-determine-date (cdr (assoc 'timestamp datapoint)) day-end))) 1786 + (aif (assoc date datapoints-by-day) 1787 + (push datapoint (cdr it)) 1788 + (push (list date datapoint) datapoints-by-day)))) 1789 + (cdr (assoc 'datapoints goal))) 1790 + datapoints-by-day)) 1791 + 1792 + ;; (defun beeminder-gather-datapoints-by-day (goal) 1793 + ;; "Return an alist of datapoints, collated by date. 1794 + ;; The car of each entry is a string representing the date in ISO 1795 + ;; 8601 basic format (i.e., \"20160417\" for April 17, 2016), and 1796 + ;; the cdr is the list of datapoints. If 1797 + ;; `beeminder-use-goal-midnight-today-values' is nil, use the goal's 1798 + ;; \"midnight\" setting to determine the date; otherwise, use 1799 + ;; `beeminder-when-the-day-ends'." 1800 + ;; (let ((day-end (if beeminder-use-goal-midnight-today-values 1801 + ;; beeminder-when-the-day-ends 1802 + ;; (cdr (assoc 'deadline goal)))) 1803 + ;; datapoints-by-day) 1804 + ;; (mapc (lambda (datapoint) 1805 + ;; (let ((date (beeminder-determine-date (cdr (assoc 'timestamp datapoint)) day-end))) 1806 + ;; (aif (assoc date datapoints-by-day) 1807 + ;; (push datapoint (cdr it)) 1808 + ;; (push (list date datapoint) datapoints-by-day)))) 1809 + ;; (cdr (assoc 'datapoints goal))) 1810 + ;; datapoints-by-day)) 1811 + 1812 + (defun beeminder-uniq-mean (list) 1813 + "Return the mean of numbers in LIST after deleting 1814 + duplicates." 1815 + (let ((list list)) 1816 + (/ (apply #'+ (delete-dups list)) 1817 + (length list) 1818 + 1.0))) 1819 + 1820 + (defun beeminder-median (list) 1821 + "Return a median of numbers in LIST. 1822 + If LIST contains an even number of elements n, return 1823 + the (n/2)-th one." 1824 + (let ((list list) median-list) 1825 + (setq list (sort list #'<) 1826 + median-list list) 1827 + (while (cddr list) 1828 + (setq median-list (cdr median-list) 1829 + list (cddr list))) 1830 + (if (cdr list) 1831 + (* 0.5 (+ (car median-list) (cadr median-list))) 1832 + (car median-list)))) 1833 + 1834 + (defvar beeminder-aggregation-methods 1835 + '(("sum" . (lambda (dps) (apply #'+ dps))) 1836 + ("last" . car) ; this is no mistake - the list is in reverse order! 1837 + ("first" . (lambda (dps) (car (last dps)))) 1838 + ("min" . (lambda (dps) (apply #'min dps))) 1839 + ("max" . (lambda (dps) (apply #'max dps))) 1840 + ("truemean" . (lambda (dps) (/ (apply #'+ dps) (length dps) 1.0))) 1841 + ("uniqmean" . beeminder-uniq-mean) 1842 + ("mean" . beeminder-uniq-mean) 1843 + ("median" . beeminder-median) 1844 + ("jolly" . (lambda (dps) (if dps 1 0))) 1845 + ("binary" . (lambda (dps) (if dps 1 0))) 1846 + ("nonzero" . (lambda (dps) (if (cl-some (lambda (dp) (not (= 0 dp))) dps) 1 0))) 1847 + ("triangle" . (lambda (dps) (let ((sum (apply #'+ dps))) (* sum (1+ sum) 0.5)))) 1848 + ("square" . (lambda (dps) (let ((sum (apply #'+ dps))) (* sum sum)))) 1849 + ("count" . length)) 1850 + "An alist mapping aggregation methods to actual functions.") 1851 + 1852 + (defun beeminder-aggregate-values (values aggday) 1853 + "Aggregate VALUES (from one day) using the AGGDAY method." 1854 + (funcall (beeminder-alist-get aggday beeminder-aggregation-methods) 1855 + values)) 1856 + 1857 + (defun beeminder-aggregate-datapoints (datapoints-by-day aggday) 1858 + "Aggregate DATAPOINTS-BY-DAY using the AGGDAY method." 1859 + (mapcar (lambda (day-datapoints) 1860 + (cons (car day-datapoints) 1861 + (beeminder-aggregate-values 1862 + (mapcar (lambda (dp) (beeminder-alist-get 'value dp)) 1863 + (cdr day-datapoints)) 1864 + aggday))) 1865 + datapoints-by-day)) 1866 + 1867 + 1868 + ;; Displaying graphs 1869 + 1870 + (defun beeminder-download-graph (slug-str) 1871 + "Download graph for goal SLUG and put it in the tmp directory, 1872 + under the \"beeminder-el\" subdirectory and filename 1873 + \"SLUG.png\". Return the full filename." 1874 + (make-directory (concat temporary-file-directory "beeminder-el") t) 1875 + (let* ((image-file (concat temporary-file-directory "beeminder-el/" slug-str ".png")) 1876 + (inhibit-message t)) 1877 + (url-copy-file (beeminder-alist-get 'graph_url (beeminder-slug-to-goal (intern slug-str))) 1878 + image-file 1879 + t) 1880 + image-file)) 1881 + 1882 + (defun beeminder-insert-graph (image) 1883 + "Insert IMAGE at end-of-buffer. Remove any existing images 1884 + first and position the point and window so that the image can be 1885 + seen next." 1886 + (remove-images (point-min) (point-max)) 1887 + (goto-char (point-max)) 1888 + (let ((inhibit-read-only t)) 1889 + (remove-images (point-min) (point-max)) 1890 + (save-excursion 1891 + (insert "\n") 1892 + (put-image image (point-max) "[Graphs are not supported in this Emacs!]"))) 1893 + (let* ((size (image-size image)) 1894 + (width (ceiling (car size))) 1895 + (height (ceiling (cdr size)))) 1896 + (fit-window-to-buffer (selected-window) height height width width)) 1897 + (recenter 0)) 1898 + 1899 + (defun beeminder-display-graph (slug-str) 1900 + "Download the graph of the goal SLUG-STR and display it. 1901 + Switch to the \"details\" buffer first if needed. Do nothing if 1902 + the graph is already displayed." 1903 + (interactive (list (if beeminder-detailed-goal 1904 + (cdr (assoc 'slug beeminder-detailed-goal)) 1905 + (cdr (assoc 'slug (current-or-read-goal)))))) 1906 + (let* ((image-file (beeminder-download-graph slug-str)) 1907 + (image (create-image image-file))) 1908 + (beeminder-display-goal-details (beeminder-slug-to-goal (intern slug-str))) 1909 + (beeminder-insert-graph image))) 1910 + 1911 + (define-key beeminder-goal-mode-map (kbd "i") #'beeminder-display-graph) 1912 + (define-key beeminder-mode-map (kbd "i") #'beeminder-display-graph) 1913 + 1914 + 1915 + ;; Org-mode integration 1916 + 1917 + (defcustom beeminder-org-inherit-beeminder-properties nil 1918 + "Make beeminder.el use property inheritance.") 1919 + 1920 + (defcustom beeminder-org-default-comment "%h at %t" 1921 + "Default format of the comment") 1922 + 1923 + (defun beeminder-org-string-substitute (string) 1924 + "Substitute strings for percent-sign codes in STRING. 1925 + Codes are: `%t' - current time, `%h' - current headline, `%p' - 1926 + current path, `%%' - percent sign." 1927 + (let ((time (beeminder-current-time-string)) 1928 + (headline (substring-no-properties (org-get-heading t t))) 1929 + (path (mapconcat #'identity (org-get-outline-path t) "/"))) 1930 + (format-spec string 1931 + `((?% . "%") 1932 + (?t . ,time) 1933 + (?h . ,headline) 1934 + (?p . ,path))))) 1935 + 1936 + (defun beeminder-org-generate-comment () 1937 + "Given the comment property, generate the comment text. Assume 1938 + that the point is in the right place." 1939 + (let ((comment-prop 1940 + (or (org-entry-get (point) 1941 + "comment" 1942 + beeminder-org-inherit-beeminder-properties) 1943 + beeminder-org-default-comment))) 1944 + (cond 1945 + ((string= comment-prop "time") 1946 + (concat "via Org-mode at " (beeminder-current-time-string))) 1947 + ((string= comment-prop "ask") 1948 + nil) 1949 + ((or (string= comment-prop "headline") 1950 + (null comment-prop)) 1951 + (substring-no-properties (org-get-heading t t))) 1952 + ((string= comment-prop "path") 1953 + (mapconcat #'identity (org-get-outline-path t) "/")) 1954 + (t (beeminder-org-string-substitute comment-prop))))) 1955 + 1956 + (defun beeminder-org-submit-on-done (state-change) 1957 + "Submit a datapoint when marking an item as DONE. 1958 + This function should be placed in `org-trigger-hook'. It looks 1959 + up the following properties of the headline: the \"beeminder\" 1960 + property (which should be set to \"done\", the \"slug\" 1961 + property (which should be set to the slug of the goal), the 1962 + \"amount\" property (defaults to 1), the \"ask-comment\" 1963 + property (asks for the comment if it is present)." 1964 + (let ((position (plist-get state-change :position))) 1965 + (if (and (string= (downcase (or (org-entry-get position 1966 + "beeminder" 1967 + beeminder-org-inherit-beeminder-properties) 1968 + "")) 1969 + "done") 1970 + (eq (plist-get state-change :type) 1971 + 'todo-state-change) 1972 + (member (plist-get state-change :to) 1973 + org-done-keywords)) 1974 + (let* ((slug-str (org-entry-get position 1975 + "slug" 1976 + beeminder-org-inherit-beeminder-properties)) 1977 + (amount (aif (org-entry-get position 1978 + "amount" 1979 + beeminder-org-inherit-beeminder-properties) 1980 + (string-to-number it) 1981 + 1)) 1982 + (comment (beeminder-org-generate-comment))) 1983 + (beeminder-submit-datapoint slug-str amount comment))))) 1984 + 1985 + (defun beeminder-org-submit-clock-at-point () 1986 + "Submit the data from the clock item at point to Beeminder. 1987 + This is mainly useful if submitting on clocking out (see 1988 + `beeminder-org-submit-on-clock-out' failed for some reason, so 1989 + that the user may want to submit clock items later." 1990 + (interactive) 1991 + (let ((element (org-element-at-point))) 1992 + (if (eq (org-element-type element) 'clock) 1993 + (let ((timestamp (org-element-property :value element)) 1994 + (duration (org-element-property :duration element))) 1995 + (when (string-match "\\([[:digit:]]+\\):\\([[:digit:]]\\{2\\}\\)" duration) 1996 + (let* ((minutes (+ (* 60 (string-to-number (match-string 1 duration))) 1997 + (string-to-number (match-string 2 duration)))) 1998 + (slug-str (org-entry-get (point) 1999 + "slug" 2000 + beeminder-org-inherit-beeminder-properties)) 2001 + (comment (beeminder-org-generate-comment)) 2002 + (multiplier (cl-case (intern (or (org-entry-get (point) 2003 + "unit" 2004 + beeminder-org-inherit-beeminder-properties) 2005 + "")) 2006 + ((hour hours) 2007 + (/ 1 60.0)) 2008 + ((hail-Mary hail-Marys) 2009 + 3) 2010 + ; 1 hail-Mary ≈ 20 seconds 2011 + (t 1))) 2012 + (year-end (org-element-property :year-end timestamp)) 2013 + (month-end (org-element-property :month-end timestamp)) 2014 + (day-end (org-element-property :day-end timestamp)) 2015 + (hour-end (org-element-property :hour-end timestamp)) 2016 + (minute-end (org-element-property :minute-end timestamp)) 2017 + (id (format "%04d%02d%02d%02d%02dto%04d%02d%02d%02d%02d" 2018 + (org-element-property :year-start timestamp) 2019 + (org-element-property :month-start timestamp) 2020 + (org-element-property :day-start timestamp) 2021 + (org-element-property :hour-start timestamp) 2022 + (org-element-property :minute-start timestamp) 2023 + year-end 2024 + month-end 2025 + day-end 2026 + hour-end 2027 + minute-end)) 2028 + (timestamp (time-to-seconds (encode-time 2029 + 0 2030 + minute-end 2031 + hour-end 2032 + day-end 2033 + month-end 2034 + year-end)))) 2035 + (beeminder-submit-datapoint slug-str (* minutes multiplier) 2036 + comment 2037 + timestamp 2038 + id)))) 2039 + (beeminder-log "no clock at point!" :nolog)))) 2040 + 2041 + (defcustom beeminder-org-submit-all-clocks-default-minutes (* 24 60) 2042 + "By default, only the clocks from this many lastminutes will be 2043 + submitted by `beeminder-org-submit-all-clocks'. Does not have to 2044 + be an integer (i.e., value like 0.5 means 30 seconds).") 2045 + 2046 + (defun beeminder-org-submit-all-clocks (begin end minutes) 2047 + "Submit all clocks from last MINUTES in the region to Beeminder. 2048 + In interactive use, use region if active and current subtree 2049 + otherwise. Use with caution!" 2050 + (interactive (if (use-region-p) 2051 + (list (region-beginning) 2052 + (region-end) 2053 + current-prefix-arg) 2054 + (list nil nil current-prefix-arg))) 2055 + (unless (numberp minutes) 2056 + (setq minutes beeminder-org-submit-all-clocks-default-minutes)) 2057 + (save-excursion 2058 + (save-restriction 2059 + (narrow-to-region 2060 + (or begin (progn (org-back-to-heading t) 2061 + (point))) 2062 + (or end (progn (org-end-of-subtree t t) 2063 + (when (and (org-at-heading-p) ; see org-narrow-to-subtree 2064 + (not (eobp))) 2065 + (backward-char 1)) 2066 + (point)))) 2067 + (goto-char (point-min)) 2068 + (while (re-search-forward "CLOCK: " nil t) 2069 + (let ((eap (org-element-at-point))) 2070 + (when (and (eq (org-element-type eap) 2071 + 'clock) 2072 + (eq (org-element-property :status eap) 2073 + 'closed)) 2074 + (let ((ts (org-element-property :value eap))) 2075 + (when (< (time-to-seconds 2076 + (time-subtract (beeminder-current-time) 2077 + (encode-time 0 2078 + (org-element-property :minute-end ts) 2079 + (org-element-property :hour-end ts) 2080 + (org-element-property :day-end ts) 2081 + (org-element-property :month-end ts) 2082 + (org-element-property :year-end ts)))) 2083 + (* 60 minutes)) 2084 + (beeminder-org-submit-clock-at-point))))))))) 2085 + 2086 + (defun beeminder-org-submit-on-clock-out () 2087 + "Submit the time clocked for this item. 2088 + This function should be placed in `org-clock-out-hook'. It looks 2089 + up the following properties of the headline: the \"beeminder\" 2090 + property (which should be set to \"clock\", the \"slug\" 2091 + property (which should be set to the slug of the goal), the 2092 + \"unit\" property (which may be \"minutes\", which is the 2093 + default, or \"hours\", etc.\"), the \"ask-comment\" 2094 + property (asks for the comment if it is present)." 2095 + (when (and (string= (downcase (or (org-entry-get (point) 2096 + "beeminder" 2097 + beeminder-org-inherit-beeminder-properties) 2098 + "")) 2099 + "clock") 2100 + (not (string-match " LINE REMOVED$" (or (current-message) ""))) ; this is really hackish 2101 + (org-entry-get 2102 + (point) "slug" beeminder-org-inherit-beeminder-properties)) 2103 + (beeminder-org-submit-clock-at-point))) 2104 + 2105 + (define-minor-mode beeminder-org-integration-mode 2106 + "Toggle a (global) minor mode for Org/Beeminder integration. 2107 + When on, clocking out and marking as DONE for headlines with suitable 2108 + :beeminder: property is submitted automatically." 2109 + :init-value nil 2110 + :global t 2111 + :lighter " B-O" 2112 + (if beeminder-org-integration-mode 2113 + (progn 2114 + (add-hook 'org-trigger-hook #'beeminder-org-submit-on-done) 2115 + (add-hook 'org-clock-out-hook #'beeminder-org-submit-on-clock-out)) 2116 + (remove-hook 'org-trigger-hook #'beeminder-org-submit-on-done) 2117 + (remove-hook 'org-clock-out-hook #'beeminder-org-submit-on-clock-out))) 2118 + 2119 + 2120 + (provide 'beeminder) 2121 + 2122 + 2123 + ;;; beeminder.el ends here
+6
spacemacs-private/snippets/README.md
··· 1 + # Private directory for Yasnippets snippets 2 + 3 + The content of this directory is ignored by Git. This is the default place 4 + where to store your private yasnippets. 5 + 6 + This path will be loaded automatically and used whenever Yasnippets loads.
+17
spacemacs-private/snippets/haskell-mode/haddock-module-desc
··· 1 + # -*- mode: snippet -*- 2 + # name: haskell haddock module description 3 + # key: had.m 4 + # expand-env: ((yas-indent-line 'fixed)) 5 + # -- 6 + --------------------------------- 7 + -- | 8 + -- Module : `(file-name-sans-extension (buffer-name))` 9 + -- Copyright : (C) Kaushik Chakraborty, `(format-time-string "%Y")` 10 + -- License : Apache v2 (see the file LICENSE) 11 + -- Maintainer : Kaushik Chakraborty <git@kaushikc.org> 12 + -- Stability : experimental 13 + --${1: 14 + -- ${2:description} 15 + --} 16 + --------------------------------- 17 + $0
+12
spacemacs-private/snippets/markdown-mode/blog-header
··· 1 + # -*- mode: snippet -*- 2 + # name: blog metadata header 3 + # key: bh 4 + # -- 5 + --- 6 + title : $1 7 + published : ${2:`(format-time-string "%Y-%m-%d")`} 8 + tags : $3 9 + link : $4 10 + --- 11 + 12 + $0
+5
spacemacs-private/snippets/markdown-mode/blog-sports-tags
··· 1 + # -*- mode: snippet -*- 2 + # name: blog-sports-tags-world-cup 3 + # key: btswc 4 + # -- 5 + sports, football, world-cup, wc-${1:`(format-time-string "%Y")`}
+9
spacemacs-private/snippets/markdown-mode/micro-blog-header
··· 1 + # -*- mode: snippet -*- 2 + # name: micro blog header 3 + # key: mbh 4 + # -- 5 + --- 6 + published : `(format-time-string "%Y-%m-%d %H:%M:%S%z")` 7 + --- 8 + 9 + $0
+40
spacemacs-private/spacemacs.env
··· 1 + ]1337;RemoteHost=kaushik@AMB00472]1337;CurrentDir=/Users/kaushik]1337;ShellIntegrationVersion=5;shell=zshPWD=/Users/kaushik 2 + LC_ALL=en_US.UTF-8 3 + LANG=en_US.UTF-8 4 + LSCOLORS=Gxfxcxdxbxegedabagacad 5 + LESS=-R 6 + PAGER=less 7 + NIX_PATH=/nix/var/nix/profiles/per-user/root/channels 8 + NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt 9 + NIX_PROFILES=/nix/var/nix/profiles/default /Users/kaushik/.nix-profile 10 + NIX_USER_PROFILE_DIR=/nix/var/nix/profiles/per-user/kaushik 11 + NIX_REMOTE=daemon 12 + PERL_LWP_SSL_VERIFY_HOSTNAME=0 13 + NO_PROXY=localhost,127.0.0.1,10.154.194.1,10.154.194.2,10.154.194.3,10.154.194.4,10.154.194.5,10.154.194.6,10.154.194.7,10.154.194.8,10.154.194.9,10.154.194.10,10.154.194.11,10.154.194.12,10.154.194.13,10.154.194.14,10.154.194.15,10.154.194.16,10.154.194.17,10.154.194.18,10.154.194.19,10.154.194.20,10.154.194.21,10.154.194.22,10.154.194.23,10.154.194.24,10.154.194.25,10.154.194.26,10.154.194.27,10.154.194.28,10.154.194.29,10.154.194.30,10.154.194.31,10.154.194.32,10.154.194.33,10.154.194.34,10.154.194.35,10.154.194.36,10.154.194.37,10.154.194.38,10.154.194.39,10.154.194.40,10.154.194.41,10.154.194.42,10.154.194.43,10.154.194.44,10.154.194.45,10.154.194.46,10.154.194.47,10.154.194.48,10.154.194.49,10.154.194.50,10.154.194.51,10.154.194.52,10.154.194.53,10.154.194.54,10.154.194.55,10.154.194.56,10.154.194.57,10.154.194.58,10.154.194.59,10.154.194.60,10.154.194.61,10.154.194.62,10.154.194.63,10.154.194.64,10.154.194.65,10.154.194.66,10.154.194.67,10.154.194.68,10.154.194.69,10.154.194.70,10.154.194.71,10.154.194.72,10.154.194.73,10.154.194.74,10.154.194.75,10.154.194.76,10.154.194.77,10.154.194.78,10.154.194.79,10.154.194.80,10.154.194.81,10.154.194.82,10.154.194.83,10.154.194.84,10.154.194.85,10.154.194.86,10.154.194.87,10.154.194.88,10.154.194.89,10.154.194.90,10.154.194.91,10.154.194.92,10.154.194.93,10.154.194.94,10.154.194.95,10.154.194.96,10.154.194.97,10.154.194.98,10.154.194.99,10.154.194.100,10.154.194.101,10.154.194.102,10.154.194.103,10.154.194.104,10.154.194.105,10.154.194.106,10.154.194.107,10.154.194.108,10.154.194.109,10.154.194.110,10.154.194.111,10.154.194.112,10.154.194.113,10.154.194.114,10.154.194.115,10.154.194.116,10.154.194.117,10.154.194.118,10.154.194.119,10.154.194.120,10.154.194.121,10.154.194.122,10.154.194.123,10.154.194.124,10.154.194.125,10.154.194.126,10.154.194.127,10.154.194.128,10.154.194.129,10.154.194.130,10.154.194.131,10.154.194.132,10.154.194.133,10.154.194.134,10.154.194.135,10.154.194.136,10.154.194.137,10.154.194.138,10.154.194.139,10.154.194.140,10.154.194.141,10.154.194.142,10.154.194.143,10.154.194.144,10.154.194.145,10.154.194.146,10.154.194.147,10.154.194.148,10.154.194.149,10.154.194.150,10.154.194.151,10.154.194.152,10.154.194.153,10.154.194.154,10.154.194.155,10.154.194.156,10.154.194.157,10.154.194.158,10.154.194.159,10.154.194.160,10.154.194.161,10.154.194.162,10.154.194.163,10.154.194.164,10.154.194.165,10.154.194.166,10.154.194.167,10.154.194.168,10.154.194.169,10.154.194.170,10.154.194.171,10.154.194.172,10.154.194.173,10.154.194.174,10.154.194.175,10.154.194.176,10.154.194.177,10.154.194.178,10.154.194.179,10.154.194.180,10.154.194.181,10.154.194.182,10.154.194.183,10.154.194.184,10.154.194.185,10.154.194.186,10.154.194.187,10.154.194.188,10.154.194.189,10.154.194.190,10.154.194.191,10.154.194.192,10.154.194.193,10.154.194.194,10.154.194.195,10.154.194.196,10.154.194.197,10.154.194.198,10.154.194.199,10.154.194.200,10.154.194.201,10.154.194.202,10.154.194.203,10.154.194.204,10.154.194.205,10.154.194.206,10.154.194.207,10.154.194.208,10.154.194.209,10.154.194.210,10.154.194.211,10.154.194.212,10.154.194.213,10.154.194.214,10.154.194.215,10.154.194.216,10.154.194.217,10.154.194.218,10.154.194.219,10.154.194.220,10.154.194.221,10.154.194.222,10.154.194.223,10.154.194.224,10.154.194.225,10.154.194.226,10.154.194.227,10.154.194.228,10.154.194.229,10.154.194.230,10.154.194.231,10.154.194.232,10.154.194.233,10.154.194.234,10.154.194.235,10.154.194.236,10.154.194.237,10.154.194.238,10.154.194.239,10.154.194.240,10.154.194.241,10.154.194.242,10.154.194.243,10.154.194.244,10.154.194.245,10.154.194.246,10.154.194.247,10.154.194.248,10.154.194.249,10.154.194.250,10.154.194.251,10.154.194.252,10.154.194.253,10.154.194.254,10.154.194.255,10.154.198.1,10.154.198.2,10.154.198.3,10.154.198.4,10.154.198.5,10.154.198.6,10.154.198.7,10.154.198.8,10.154.198.9,10.154.198.10,10.154.198.11,10.154.198.12,10.154.198.13,10.154.198.14,10.154.198.15,10.154.198.16,10.154.198.17,10.154.198.18,10.154.198.19,10.154.198.20,10.154.198.21,10.154.198.22,10.154.198.23,10.154.198.24,10.154.198.25,10.154.198.26,10.154.198.27,10.154.198.28,10.154.198.29,10.154.198.30,10.154.198.31,10.154.198.32,10.154.198.33,10.154.198.34,10.154.198.35,10.154.198.36,10.154.198.37,10.154.198.38,10.154.198.39,10.154.198.40,10.154.198.41,10.154.198.42,10.154.198.43,10.154.198.44,10.154.198.45,10.154.198.46,10.154.198.47,10.154.198.48,10.154.198.49,10.154.198.50,10.154.198.51,10.154.198.52,10.154.198.53,10.154.198.54,10.154.198.55,10.154.198.56,10.154.198.57,10.154.198.58,10.154.198.59,10.154.198.60,10.154.198.61,10.154.198.62,10.154.198.63,10.154.198.64,10.154.198.65,10.154.198.66,10.154.198.67,10.154.198.68,10.154.198.69,10.154.198.70,10.154.198.71,10.154.198.72,10.154.198.73,10.154.198.74,10.154.198.75,10.154.198.76,10.154.198.77,10.154.198.78,10.154.198.79,10.154.198.80,10.154.198.81,10.154.198.82,10.154.198.83,10.154.198.84,10.154.198.85,10.154.198.86,10.154.198.87,10.154.198.88,10.154.198.89,10.154.198.90,10.154.198.91,10.154.198.92,10.154.198.93,10.154.198.94,10.154.198.95,10.154.198.96,10.154.198.97,10.154.198.98,10.154.198.99,10.154.198.100,10.154.198.101,10.154.198.102,10.154.198.103,10.154.198.104,10.154.198.105,10.154.198.106,10.154.198.107,10.154.198.108,10.154.198.109,10.154.198.110,10.154.198.111,10.154.198.112,10.154.198.113,10.154.198.114,10.154.198.115,10.154.198.116,10.154.198.117,10.154.198.118,10.154.198.119,10.154.198.120,10.154.198.121,10.154.198.122,10.154.198.123,10.154.198.124,10.154.198.125,10.154.198.126,10.154.198.127,10.154.198.128,10.154.198.129,10.154.198.130,10.154.198.131,10.154.198.132,10.154.198.133,10.154.198.134,10.154.198.135,10.154.198.136,10.154.198.137,10.154.198.138,10.154.198.139,10.154.198.140,10.154.198.141,10.154.198.142,10.154.198.143,10.154.198.144,10.154.198.145,10.154.198.146,10.154.198.147,10.154.198.148,10.154.198.149,10.154.198.150,10.154.198.151,10.154.198.152,10.154.198.153,10.154.198.154,10.154.198.155,10.154.198.156,10.154.198.157,10.154.198.158,10.154.198.159,10.154.198.160,10.154.198.161,10.154.198.162,10.154.198.163,10.154.198.164,10.154.198.165,10.154.198.166,10.154.198.167,10.154.198.168,10.154.198.169,10.154.198.170,10.154.198.171,10.154.198.172,10.154.198.173,10.154.198.174,10.154.198.175,10.154.198.176,10.154.198.177,10.154.198.178,10.154.198.179,10.154.198.180,10.154.198.181,10.154.198.182,10.154.198.183,10.154.198.184,10.154.198.185,10.154.198.186,10.154.198.187,10.154.198.188,10.154.198.189,10.154.198.190,10.154.198.191,10.154.198.192,10.154.198.193,10.154.198.194,10.154.198.195,10.154.198.196,10.154.198.197,10.154.198.198,10.154.198.199,10.154.198.200,10.154.198.201,10.154.198.202,10.154.198.203,10.154.198.204,10.154.198.205,10.154.198.206,10.154.198.207,10.154.198.208,10.154.198.209,10.154.198.210,10.154.198.211,10.154.198.212,10.154.198.213,10.154.198.214,10.154.198.215,10.154.198.216,10.154.198.217,10.154.198.218,10.154.198.219,10.154.198.220,10.154.198.221,10.154.198.222,10.154.198.223,10.154.198.224,10.154.198.225,10.154.198.226,10.154.198.227,10.154.198.228,10.154.198.229,10.154.198.230,10.154.198.231,10.154.198.232,10.154.198.233,10.154.198.234,10.154.198.235,10.154.198.236,10.154.198.237,10.154.198.238,10.154.198.239,10.154.198.240,10.154.198.241,10.154.198.242,10.154.198.243,10.154.198.244,10.154.198.245,10.154.198.246,10.154.198.247,10.154.198.248,10.154.198.249,10.154.198.250,10.154.198.251,10.154.198.252,10.154.198.253,10.154.198.254,10.154.198.255 14 + AWS_PROFILE=kube-aws-admin 15 + COURSIER_CACHE=/Users/kaushik/Developer/repo/sbt/coursier/ 16 + ZSH=/Users/kaushik/.oh-my-zsh 17 + OLDPWD=/Users/kaushik 18 + SHLVL=1 19 + ITERM_SESSION_ID=w2t1p0:A0182136-1AD9-4C15-AB89-38DE7ECB78D6 20 + __CF_USER_TEXT_ENCODING=0x1F5:0x0:0x0 21 + LOGNAME=kaushik 22 + XPC_SERVICE_NAME=0 23 + USER=kaushik 24 + TMPDIR=/var/folders/4m/8lbd4pzn2z73b5zjzbbpc0tc0000gn/T/ 25 + HOME=/Users/kaushik 26 + TERM=xterm-256color 27 + COLORTERM=truecolor 28 + DISPLAY=/private/tmp/com.apple.launchd.p4S0G7dI7F/org.macosforge.xquartz:0 29 + PATH=/Users/kaushik/.local/bin/luna-studio:/Users/kaushik/bin:/Users/kaushik/.local/bin:/usr/local/bin:/Users/kaushik/.nix-profile/bin:/Users/kaushik/.nix-profile/lib/kde4/libexec:/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default:/nix/var/nix/profiles/default/lib/kde4/libexec:/Users/kaushik/Library/Python/2.7/bin:/opt/local/bin:/Users/kaushik/bin:/Users/kaushik/.local/bin:/usr/local/bin:/Users/kaushik/.local/bin/luna-studio:/Users/kaushik/bin:/Users/kaushik/.local/bin:/usr/local/bin:/Users/kaushik/.nix-profile/bin:/Users/kaushik/.nix-profile/lib/kde4/libexec:/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default:/nix/var/nix/profiles/default/lib/kde4/libexec:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/TeX/texbin:/usr/local/MacGPG2/bin:/opt/X11/bin:/Users/kaushik/Library/Python/2.7/bin:/opt/local/bin:/Users/kaushik/bin:/Users/kaushik/.local/bin:/Applications/Emacs.app/Contents/MacOS/bin-x86_64-10_9:/Applications/Emacs.app/Contents/MacOS/libexec-x86_64-10_9 30 + TERM_PROGRAM=iTerm.app 31 + TERM_PROGRAM_VERSION=3.1.6 32 + LC_CTYPE=UTF-8 33 + SHELL=/bin/zsh 34 + XPC_FLAGS=0x0 35 + ITERM_PROFILE=Default 36 + COLORFGBG=11;15 37 + Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.L8tyLG5nky/Render 38 + SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.ThFPgG6osR/Listeners 39 + TERM_SESSION_ID=w2t1p0:A0182136-1AD9-4C15-AB89-38DE7ECB78D6 40 + _=/usr/bin/env
+6
spacemacs-private/templates/README.md
··· 1 + # Private directory for Yatemplate templates 2 + 3 + The content of this directory is ignored by Git. This is the default place 4 + where to store your private templates. 5 + 6 + This path will be loaded automatically and used whenever Yatemplate loads.