diff --git a/lisp/my-view.el b/lisp/my-view.el new file mode 100644 index 00000000..f1687f5c --- /dev/null +++ b/lisp/my-view.el @@ -0,0 +1,111 @@ +;;; my-view.el --- Personal library view -*- lexical-binding: t -*- + +;;; Commentary: + +;;; Code: +(defun my-view-python () + "Three windows. +On the right side a *Anaconda* buffer with optionally +`virtual-auto-fill-mode' active and a *Python* buffer." + (interactive) + (require 'python) + + (unless (get-buffer (concat "*" python-shell-buffer-name "*")) + (run-python) ;; cursor is now inside the python buffer. + (other-window -1)) + + (delete-other-windows) + + (split-window-horizontally (truncate (* 0.6 (window-body-width)))) + (other-window 1) + (switch-to-buffer (concat "*" python-shell-buffer-name "*")) + + (split-window-vertically) ;; both are python buffers now. + (switch-to-buffer "*Anaconda*") + (when (fboundp 'virtual-auto-fill-mode) (virtual-auto-fill-mode)) + (other-window -1)) + +(defun my-view-elisp () + "Two windows side-by-side. +On the right side a *Help* buffer with optionally +`virtual-auto-fill-mode' active." + (interactive) + (delete-other-windows) + + (split-window-horizontally (truncate (* 0.6 (window-body-width)))) + (other-window 1) + (switch-to-buffer "*Help*") + (other-window -1)) + +(defun my-view-shell () + "Two windows side-by-side. +On the right side a *compilation* buffer. +Use `compile' with `sh ' to run the script." + ;; TODO: rebind compile to C-c and auto fill sh with filename + ;; TODO: rebind recompile to ??? to use last compile command + ;; https://masteringemacs.org/article/compiling-running-scripts-emacs + ;; TODO: for shell-script buffers: + ;; ;;; Shut up compile saves + ;; (setq compilation-ask-about-save nil) + ;; ;;; Don't save *anything* + ;; (setq compilation-save-buffers-predicate '(lambda () nil)) + (interactive) + (delete-other-windows) + + (split-window-horizontally (truncate (* 0.6 (window-body-width)))) + (other-window 1) + (switch-to-buffer "*compilation*") + (other-window -1)) + +(defun my-view-org-pdf () + "Two windows side-by-side. +On the right side a DocView buffer displaying the pdf." + (interactive) + (delete-other-windows) + (let ((bufnam (buffer-name)) + (buffilnam buffer-file-name)) + (split-window-horizontally) + (other-window 1) + ;;(switch-to-buffer (concat (file-name-sans-extension bufnam) ".pdf")) + (find-file (concat (file-name-sans-extension buffilnam) ".pdf")) + (doc-view-fit-height-to-window) + (doc-view-fit-window-to-page) + (other-window -1))) + +(defun my-view-gnuplot () + "Three windows. +On the right side a *Shell* buffer with optionally +`virtual-auto-fill-mode' active and an Image mode buffer." + (interactive) + + (save-excursion + (let (output-file-name) ;; get figure output name + (goto-char (point-min)) + (when (re-search-forward "set output .*" nil t) + ;; TODO: search text in between set output '...' then I do not + ;; need to replace / remove part of the match string. + (setq output-file-name (match-string 0)) + (setq output-file-name (string-replace "set output " "" output-file-name)) + (setq output-file-name (substring output-file-name 1 -1))) + ;;(message "%s" output-file-name) + + (delete-other-windows) + + (split-window-horizontally (truncate (* 0.6 (window-body-width)))) + (other-window 1) + (if output-file-name + ;;(switch-to-buffer output-file-name) + (find-file output-file-name) + ;;(switch-to-buffer "*scratch*") + (switch-to-buffer " *image*")) + ;;(when (fboundp 'virtual-auto-fill-mode) (virtual-auto-fill-mode)) + + (split-window-vertically) ;; both are shell buffers now. + (switch-to-buffer "*shell*") + (shell) + ;;(when (fboundp 'virtual-auto-fill-mode) (virtual-auto-fill-mode)) + + (other-window -1)))) + +(provide 'my-view) +;;; my-view.el ends here diff --git a/lisp/my.el b/lisp/my.el index dfc84404..054bf4df 100644 --- a/lisp/my.el +++ b/lisp/my.el @@ -24,6 +24,10 @@ :prefix "my-" :group 'emacs) +(defun my-eval-string (string) + "Evaluate elisp code stored in a string." + (eval (car (read-from-string (format "(progn %s)" string))))) + (defun my-list-delete (element list) "Destructive version of `delete'. LIST will be nil if the last ELEMENT was deleted. @@ -36,6 +40,21 @@ Example: (my-list-delete '(\"a\") 'my-list)" (set list (delete element (symbol-value list)))) +(defun my-list-to-org-table (lst) + "Convert list into an Org table." + (let ((lines lst) + (rows) + (tbl)) + (while lines + (setq rows (car lines)) + (setq tbl (concat tbl "|")) + (while rows + (setq tbl (concat tbl (format "%s|" (car rows)))) + (setq rows (cdr rows))) + (setq tbl (concat tbl "\n")) + (setq lines (cdr lines))) + tbl)) + (defmacro my-plist-put (plist &rest args) "Example usage: (my-plist-put my-org-table-colored-cells 'table-name '(\"@23$3\" \"blue\")) @@ -397,114 +416,5 @@ Usage: ) ;; with-eval-after-load 'org -(defun my-view-python () - "Three windows. -On the right side a *Anaconda* buffer with optionally -`virtual-auto-fill-mode' active and a *Python* buffer." - (interactive) - (require 'python) - - (unless (get-buffer (concat "*" python-shell-buffer-name "*")) - (run-python) ;; cursor is now inside the python buffer. - (other-window -1) - ) - - (delete-other-windows) - - (split-window-horizontally (truncate (* 0.6 (window-body-width)))) - (other-window 1) - (switch-to-buffer (concat "*" python-shell-buffer-name "*")) - - (split-window-vertically) ;; both are python buffers now. - (switch-to-buffer "*Anaconda*") - (when (fboundp 'virtual-auto-fill-mode) (virtual-auto-fill-mode)) - (other-window -1) - ) - -(defun my-view-elisp () - "Two windows side-by-side. -On the right side a *Help* buffer with optionally -`virtual-auto-fill-mode' active." - (interactive) - (delete-other-windows) - - (split-window-horizontally (truncate (* 0.6 (window-body-width)))) - (other-window 1) - (switch-to-buffer "*Help*") - (other-window -1) - ) - -(defun my-view-shell () - "Two windows side-by-side. -On the right side a *compilation* buffer. -Use `compile' with `sh ' to run the script." - ;; TODO: rebind compile to C-c and auto fill sh with filename - ;; TODO: rebind recompile to ??? to use last compile command - ;; https://masteringemacs.org/article/compiling-running-scripts-emacs - ;; TODO: for shell-script buffers: - ;; ;;; Shut up compile saves - ;; (setq compilation-ask-about-save nil) - ;; ;;; Don't save *anything* - ;; (setq compilation-save-buffers-predicate '(lambda () nil)) - (interactive) - (delete-other-windows) - - (split-window-horizontally (truncate (* 0.6 (window-body-width)))) - (other-window 1) - (switch-to-buffer "*compilation*") - (other-window -1) - ) - -(defun my-view-org-pdf () - "Two windows side-by-side. -On the right side a DocView buffer displaying the pdf." - (interactive) - (delete-other-windows) - (let ((bufnam (buffer-name)) - (buffilnam buffer-file-name)) - (split-window-horizontally) - (other-window 1) - ;;(switch-to-buffer (concat (file-name-sans-extension bufnam) ".pdf")) - (find-file (concat (file-name-sans-extension buffilnam) ".pdf")) - (doc-view-fit-height-to-window) - (doc-view-fit-window-to-page) - (other-window -1) - )) - -(defun my-view-gnuplot () - "Three windows. -On the right side a *Shell* buffer with optionally -`virtual-auto-fill-mode' active and an Image mode buffer." - (interactive) - - (save-excursion - (let (output-file-name) ;; get figure output name - (goto-char (point-min)) - (when (re-search-forward "set output .*" nil t) - ;; TODO: search text in between set output '...' then I do not - ;; need to replace / remove part of the match string. - (setq output-file-name (match-string 0)) - (setq output-file-name (string-replace "set output " "" output-file-name)) - (setq output-file-name (substring output-file-name 1 -1))) - ;;(message "%s" output-file-name) - - (delete-other-windows) - - (split-window-horizontally (truncate (* 0.6 (window-body-width)))) - (other-window 1) - (if output-file-name - ;;(switch-to-buffer output-file-name) - (find-file output-file-name) - ;;(switch-to-buffer "*scratch*") - (switch-to-buffer " *image*")) - ;;(when (fboundp 'virtual-auto-fill-mode) (virtual-auto-fill-mode)) - - (split-window-vertically) ;; both are shell buffers now. - (switch-to-buffer "*shell*") - (shell) - ;;(when (fboundp 'virtual-auto-fill-mode) (virtual-auto-fill-mode)) - - (other-window -1)))) - (provide 'my) ;;; my.el ends here diff --git a/lisp/my/my.el b/lisp/my/my.el new file mode 100644 index 00000000..dfc84404 --- /dev/null +++ b/lisp/my/my.el @@ -0,0 +1,510 @@ +;;; my.el --- Personal library -*- lexical-binding: t -*- + +;;; Commentary: +;; Org: +;; Colored text in Org buffer and export. +;; [[color:gray][text]] +;; [[color:#cccccc][text]] + +;;; Code: +;; ELisp: +;; (equal (symbol-name 'tmp) "tmp") ;; get symbol as string and compare with string +;; (equal (intern "tmp") 'tmp) ;; get string as symbol and compare with symbol +;; (regexp-quote "/foo/baz/*") ;; => "/foo/baz/\\*" +;; (add-hook 'help-mode-hook 'virtual-auto-fill-mode) ;; add a mode-hook +;; (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook 'a-test-save-hook nil t))) ;; add local hook to a mode-hook +;; Org: +;; https://orgmode.org/worg/dev/org-element-api.html +;; https://orgmode.org/worg/dev/org-syntax.html +;; Over an element, like a table. The key must start with attr_. +;; The lower line shows the plist elements inside the org element context. + +(defgroup my nil + "My concept mapping" + :prefix "my-" + :group 'emacs) + +(defun my-list-delete (element list) + "Destructive version of `delete'. +LIST will be nil if the last ELEMENT was deleted. +Example: + (setq my-list '(\"a\")) + (my-list-delete \"a\" 'my-list) + (setq my-list '(a)) + (my-list-delete 'a 'my-list) + (add-to-list 'my-list '(\"a\")) + (my-list-delete '(\"a\") 'my-list)" + (set list (delete element (symbol-value list)))) + +(defmacro my-plist-put (plist &rest args) + "Example usage: + (my-plist-put my-org-table-colored-cells 'table-name '(\"@23$3\" \"blue\")) + (my-plist-put my-org-table-colored-cells + 'table-name-1 '(\"@13$3\" \"red\") 'table-name-2 '(\"@33$3\" \"green\"))" + (let ((list nil)) + (while args + (push `(setq ,plist (plist-put ,plist ,(pop args) ,(pop args))) list)) + (cons 'progn (nreverse list)))) + +(defun my-interpolate (low high r rlow rhigh) + "Return the point between LOW and HIGH that corresponds to where R is \ +between RLOW and RHIGH. + +Linear interpolate of R in the interval RLOW RHIGH. + +RESULT - LOW HIGH - LOW +------------ = ------------ + R - RLOW RHIGH - RLOW + + HIGH - LOW +RESULT = LOW + (R - RLOW) * ------------ + RHIGH - RLOW + +Example: + (my-interpolate 0 100 12 0 10) => 120" + (+ low (/ (* (- high low) (- r rlow)) (- rhigh rlow)))) + +(defun my-color-luminance (R G B) + "Luminosity, relative luminance. + +L = 0.2126*R' + 0.7152*G' + 0.0722*B' with +[R',G',B'] = [R,G,B] / 12.92 if [R,G,B] <= 0.03928 else (([R,G,B]+0.055)/1.055)^2.4 +earlier +L = 0.2126*R^2.2 + 0.7152*G^2.2 + 0.0722*B^2.2 + +R,G,B,L = [0, 1] +See also `my-color-contrast'" + ;; https://www.w3.org/Graphics/Color/sRGB.html + (let ((R (if (<= R 0.03928) (/ R 12.92) (expt (/ (+ R 0.055) 1.055) 2.4))) + (G (if (<= G 0.03928) (/ G 12.92) (expt (/ (+ G 0.055) 1.055) 2.4))) + (B (if (<= B 0.03928) (/ B 12.92) (expt (/ (+ B 0.055) 1.055) 2.4)))) + (+ (* 0.2126 R) (* 0.7152 G) (* 0.0722 B))) + ;; earlier + ;;(+ (* 0.2126 (expt R 2.2)) (* 0.7152 (expt G 2.2)) (* 0.0722 (expt B 2.2))) + ) + +(defun my-color-contrast (R1 G1 B1 &optional R2 G2 B2) + "Luminosity contrast ratio. +Calculate the difference between the given colors R1, G1, B1 and R2, +G2, B2. The returned value should be greater than or equal to 4.5 +\(earlier greater than 5) for best readability. Using +`my-color-luminance'. R2, G2, B2 defaults to black. See also +`color-dark-p'." + ;; https://www.w3.org/TR/WCAG20/#contrast-ratiodef + ;; https://www.w3.org/TR/2016/NOTE-WCAG20-TECHS-20161007/G18 + (let* ((L1 (my-color-luminance R1 G1 B1)) + (R2 (if R2 R2 0)) (G2 (if G2 G2 0)) (B2 (if B2 B2 0)) + (L2 (my-color-luminance R2 G2 B2))) + (if (> L1 L2) ;; normally L1 defined as the lighter color and L2 as the darker color + (/ (+ L1 0.05) (+ L2 0.05)) + (/ (+ L2 0.05) (+ L1 0.05))))) + +(defun my-color-rgb-gradient (rgbsteps position) + "RGBSTEPS is a list of four element lists. +The list consists +- a start position value for the color d +- and the three color parameters r g b +- example + '((d1 r1 g1 b1) + (d2 r2 g2 b2) + (d3 r3 g3 b3) + (d4 r4 g4 b4)) + with d1 < d2 < d3 < d4 +if POSITION <= d1 then return (r1 g1 b1) +else remove the rgbstep_i where POSITION > di+1 from RGBSTEPS +if there is only one rgbstep left in RGBSTEPS return the (rn gn bn) values +otherwise interpolate of the first two rgbstep elements of the remaining +RGBSTEPS list. + +Examples: + (my-rgb-gradient '((1 1 1 1) (2 2 2 2) (3 3 3 3)) 2) + (my-rgb-gradient '((1 1 1 1) (2 2 2 2)) 2)" + ;; if position <= first element of first element (d1) + ;; then return other elements of first element (r1 g1 b1) + (if (<= position (caar rgbsteps)) + (cdar rgbsteps) + ;; if there are other elements and if position > d1(,new) of the first other element + ;; then remove first element + (while (and (cdr rgbsteps) (> position (caadr rgbsteps))) + (setq rgbsteps (cdr rgbsteps))) + ;; if there is no other element, return other elements (rn gn bn) of the element in list + (if (null (cdr rgbsteps)) + (cdar rgbsteps) + ;; else there are at least two elements left. + ;; return interpolation of the first two elements + (list + ;; r1 g1 b1 r2 g2 b2 d1 d2 + (my-interpolate (nth 1 (car rgbsteps)) (nth 1 (cadr rgbsteps)) position (caar rgbsteps) (caadr rgbsteps)) + (my-interpolate (nth 2 (car rgbsteps)) (nth 2 (cadr rgbsteps)) position (caar rgbsteps) (caadr rgbsteps)) + (my-interpolate (nth 3 (car rgbsteps)) (nth 3 (cadr rgbsteps)) position (caar rgbsteps) (caadr rgbsteps)))))) + +(with-eval-after-load 'org + + ;;; colored table cells + ;; https://emacs.stackexchange.com/questions/7375/can-i-format-cells-in-an-org-mode-table-differently-depending-on-a-formula + (require 'ov) + + (defun my-org-keywords () + "Parse the buffer and return a cons list of (key . value) +from lines like: +#+KEY: value" + (org-element-map (org-element-parse-buffer 'greater-element) 'keyword + (lambda (keyword) (cons (org-element-property :key keyword) + (org-element-property :value keyword))))) + + (defun my-org-keyword (keyword) + "Get the value of a KEYWORD in the form of #+KEYWORD: value + +Using `my-org-keywords' to find all keywords." + (cdr (assoc keyword (my-org-keywords)))) + + (defun my-org-keyword-re (KEYWORD) + "Get the value from a line like this +#+KEYWORD: value +in a buffer. + +Using a case-insensitive regular expressions search in the buffer to grab the value." + (interactive) + (let ((case-fold-search t) + (re (format "^#\\+%s:[ \t]+\\([^\t\n]+\\)" KEYWORD))) + (if (not (save-excursion + (or (re-search-forward re nil t) + (re-search-backward re nil t)))) + (error (format "No line containing #+%s: value found" KEYWORD))) + (match-string 1))) + + (defun my-org-attr-to-list (attr) + " +ATTR is the for example (plist-get table :attr_color) + +#+ATTR_MY_KEY: this and that +:attr_my_key (\"this and that\") + +#+ATTR_MY_KEY: this and that +#+ATTR_MY_KEY: foo baz +:attr_my_key (\"this and that\" \"foo baz\")" + ;;(split-string (car attr)) ;; this was only the first string, meaning only one (the last) attr_color line. + ;;(split-string (string-join attr " ")) ;; splits on space but also inside quotes + (split-string-and-unquote (string-join attr " "))) + + (defun my-org-table-get () + "Check if cursor is inside an Org table or on #+TBLFM lines \ +then return the table element otherwise return nil. +`org-at-table-p' is nil if cursor on #+TBLFM" + (let ((element (org-element-at-point))) ;; get org element + (while (and element (not (eq (car element) 'table))) ;; check if it is table + (setq element (plist-get (cadr element) :parent))) ;; if not check if parent element is table + (cond + ((equal (car element) 'table) ;; only if table found + (cadr element))))) ;; return element + + (defun my-org-table-range-to-list (desc &optional val) + " +Example usage: +\(my-org-table-range-to-list \"@3$1\") -> (@3$1) +\(my-org-table-range-to-list \"@3$1\" \"red\") -> (@3$1 red) +\(my-org-table-range-to-list \"@3$1..@3$3\") -> (@3$1 @3$2 @3$3) +\(my-org-table-range-to-list \"@3$1..@3$3\" \"red\") -> (@3$1 red @3$2 red @3$3 red) + +Used in `my-org-table-list-of-range-to-list'" + (if (string-match-p (regexp-quote "..") desc) + (let (from-row from-column to-row to-column result) + (string-match "@\\([0-9]+\\)\$\\([0-9]+\\)\\.\\.@\\([0-9]+\\)\$\\([0-9]+\\)" desc) + (setq from-row (string-to-number (match-string 1 desc))) ;; 1st parentheses match from string-match + (setq from-column (string-to-number (match-string 2 desc))) ;; 2nd parentheses match from string-match + (setq to-row (string-to-number (match-string 3 desc))) ;; 3rd parentheses match from string-match + (setq to-column (string-to-number (match-string 4 desc))) ;; 4th parentheses match from string-match + (loop for i upfrom to-row downto from-row ;; push prepends + do + (cl-loop for j upfrom to-column downto from-column + do + (when val (push val result)) ;; push prepends + (push (concat "@" (number-to-string i) "$" (number-to-string j)) result) + )) + result) + (if val (list desc val) (list desc)))) + + (defun my-org-table-list-of-range-to-list (seq) + " +@3$1..@3$3 red @1$3 #0055aa -> (@3$1 red @3$2 red @3$3 red @1$3 #0055aa) + +Used in `my-org-table-cell-color-attr' +uses `my-org-table-range-to-list'" + (when seq + (let (result) + ;;(message "%s" seq) + (while seq + (setq result + (append result + (my-org-table-range-to-list (car seq) (cadr seq)))) + (setq seq (cddr seq))) + result))) + + (defun my-org-table-cell-color (beg end seq) + "BEG and END are the beginning and the end of the table. +SEQ is a list of cell name and color name pairs." + (save-excursion ;; save cursor and go back to it after, important for other features + (goto-char beg) ;; go inside the table, required for org-table-analyse + (org-table-analyze) ;; required for org-table-goto-field + (ov-clear beg end) + (while seq ;; run as long elements are in list + (let* ((cell (car seq)) ;; get first "key" + (color-name (cadr seq)) ;; get first "value" + (color-rgb (color-name-to-rgb color-name)) + (bg (apply #'color-rgb-to-hex color-rgb)) + ;;(fg (if (>= (apply #'my-color-contrast color-rgb) 4.5) "#000000" "#ffffff")) + (fg (if (>= (apply #'my-color-contrast (append color-rgb (color-name-to-rgb "gray10"))) 4.5) "gray10" "gray80")) + ;;(fg (if (>= (apply #'my-color-contrast color-rgb) 4.5) "gray10" 'default)) + (beg (progn (org-table-goto-field cell) (backward-char) (point))) ;; beginning of the cell + ;;(end (progn (org-table-end-of-field 1) (forward-char) (point))) ;; for left aligned cells end is end of content not of cell + (end (1- (plist-get (cadr (org-element-context)) :end))) + ) + (ov beg end 'face (list :background bg + :foreground fg)) + (setq seq (cddr seq)))))) ;; remove first element from list + + (defvar-local my-org-table-cell-color-list + nil + "Plist of table names with list of cells to color. +It is used for the function `my-org-table-cell-color-var'. +Example usage: + (my-plist-put my-org-table-cell-color-list 'table-name '(\"@23$3\" \"blue\")) + (setq my-org-table-cell-color-list '( + table-name-1 ( + \"@33$3\" \"blue\" + \"@34$2\" \"red\" + \"@34$3\" \"green\" + ) + table-name-2 (\"@13$3\" \"blue\" \"@14$2\" \"red\" \"@14$3\" \"green\") + ))") + + (defun my-org-table-cell-color-var () + "Function to color cells. +It uses the variable `my-org-table-cell-color-list'. +Example usage to add a (normal, global) hook: + (add-hook 'org-ctrl-c-ctrl-c-hook 'my-org-table-cell-color-var) +Example usage to add a local hook: + (add-hook 'org-ctrl-c-ctrl-c-hook 'my-org-table-cell-color-var nil t)" + (let* ((table (my-org-table-get)) ;; get table element + (table-name (plist-get table :name))) ;; get table name (string) + (cond + (table-name ;; only if table found + (let ((begcont (plist-get table :contents-begin)) ;; :begin at the beginning of #+NAME:, #+ATTR_... + (endcont (plist-get table :contents-end)) ;; :end at the end of #+TBLFM: ... + (tmp-list (plist-get my-org-table-cell-color-list (intern table-name)))) ;; get value of key (string to symbol) + (my-org-table-cell-color begcont endcont tmp-list)))))) + + (defun my-org-table-cell-color-attr () + "Function to color cells. +It uses the Org keyword #+ATTR_COLOR: CELL COLOR ... +COLOR is either a color name (see `list-colors-display') or a +Multiple #+ATTR_COLOR are possible. They are joint together. +Example usage to add a (normal, global) hook: + (add-hook 'org-ctrl-c-ctrl-c-hook 'my-org-table-cell-color-attr) +Example usage to add a local hook: + (add-hook 'org-ctrl-c-ctrl-c-hook 'my-org-table-cell-color-attr nil t) +Example usage +#+ATTR_COLOR: @1$3 #0055aa @1$1 #887744 @1$2 #008822 +#+ATTR_COLOR: @2$3 blue @2$1 yellow @2$2 green +#+ATTR_COLOR: @3$1..@4$3 #cc0000 @5$3 red +" + (let* ((table (my-org-table-get)) ;; get table element + (table-attr (plist-get table :attr_color))) ;; nil if attr not set, table can be nil + (cond + (table-attr ;; only if table attr found + (let ((begcont (plist-get table :contents-begin)) ;; :begin at the beginning of #+NAME:, #+ATTR_... + (endcont (plist-get table :contents-end)) ;; :end at the end of #+TBLFM: ... + (color-list + (my-org-table-list-of-range-to-list + (my-org-attr-to-list table-attr)))) + (my-org-table-cell-color begcont endcont color-list)))))) + + ;; colored text in org-mode using links + ;; http://kitchingroup.cheme.cmu.edu/blog/2016/01/16/Colored-text-in-org-mode-with-export-to-HTML/ + ;; https://en.wikibooks.org/wiki/LaTeX/Colors + ;; this will be evaluated during export + (require 'ol) + (require 'color) + (require 'ov) + (org-link-set-parameters + "color" + :follow + ;;(org-add-link-type + ;; "color" + '(lambda (path) + "No follow action.") + :export + '(lambda (color description backend) + "if link description is empty use color as description. +[[color:COLOR][DESCRIPTION]]" + (cond + ((eq backend 'html) + (let ((rgb (color-name-to-rgb color)) + r g b) + (if rgb + (progn + (setq r (truncate (* 255 (nth 0 rgb)))) + (setq g (truncate (* 255 (nth 1 rgb)))) + (setq b (truncate (* 255 (nth 2 rgb)))) + (format "%s" + r g b + (or description color))) + (format "No Color RGB for %s" color)))) + ((eq backend 'latex) + (let ((rgb (color-name-to-rgb color))) + (if rgb + (progn + (format "\\textcolor[rgb]{%s,%s,%s}{%s}" + (nth 0 rgb) (nth 1 rgb) (nth 2 rgb) + (or description color))) + (format "No Color RGB for %s" color)))) + ))) + (defun my-org-link-color (limit) + "Helper function for colored text in buffer. +Usage: + [[color:gray][text]] + [[color:#cccccc][text]]" + (when (re-search-forward + "color:[#0-9a-zA-Z]\\{2,\\}" limit t) + (forward-char -2) + (let ((link (org-element-context)) + color beg end post-blanks) + (if link + (progn + (setq color (org-element-property :path link) + beg (org-element-property :begin link) + end (org-element-property :end link) + post-blanks (org-element-property :post-blank link)) + (set-match-data + (list beg + (- end post-blanks))) + (ov-clear beg end 'color) + (ov beg + (- end post-blanks) + 'color t + 'face + `((:foreground ,color))) + (goto-char end)) + (goto-char limit) + nil)))) + (defun my-org-link-color-hook () + "activate with e.g. (add-hook 'org-mode-hook 'my-org-link-color-hook)" + (font-lock-add-keywords + nil + '((my-org-link-color (0 'org-link t))) + t) + ) + + ) ;; with-eval-after-load 'org + +(defun my-view-python () + "Three windows. +On the right side a *Anaconda* buffer with optionally +`virtual-auto-fill-mode' active and a *Python* buffer." + (interactive) + (require 'python) + + (unless (get-buffer (concat "*" python-shell-buffer-name "*")) + (run-python) ;; cursor is now inside the python buffer. + (other-window -1) + ) + + (delete-other-windows) + + (split-window-horizontally (truncate (* 0.6 (window-body-width)))) + (other-window 1) + (switch-to-buffer (concat "*" python-shell-buffer-name "*")) + + (split-window-vertically) ;; both are python buffers now. + (switch-to-buffer "*Anaconda*") + (when (fboundp 'virtual-auto-fill-mode) (virtual-auto-fill-mode)) + (other-window -1) + ) + +(defun my-view-elisp () + "Two windows side-by-side. +On the right side a *Help* buffer with optionally +`virtual-auto-fill-mode' active." + (interactive) + (delete-other-windows) + + (split-window-horizontally (truncate (* 0.6 (window-body-width)))) + (other-window 1) + (switch-to-buffer "*Help*") + (other-window -1) + ) + +(defun my-view-shell () + "Two windows side-by-side. +On the right side a *compilation* buffer. +Use `compile' with `sh ' to run the script." + ;; TODO: rebind compile to C-c and auto fill sh with filename + ;; TODO: rebind recompile to ??? to use last compile command + ;; https://masteringemacs.org/article/compiling-running-scripts-emacs + ;; TODO: for shell-script buffers: + ;; ;;; Shut up compile saves + ;; (setq compilation-ask-about-save nil) + ;; ;;; Don't save *anything* + ;; (setq compilation-save-buffers-predicate '(lambda () nil)) + (interactive) + (delete-other-windows) + + (split-window-horizontally (truncate (* 0.6 (window-body-width)))) + (other-window 1) + (switch-to-buffer "*compilation*") + (other-window -1) + ) + +(defun my-view-org-pdf () + "Two windows side-by-side. +On the right side a DocView buffer displaying the pdf." + (interactive) + (delete-other-windows) + (let ((bufnam (buffer-name)) + (buffilnam buffer-file-name)) + (split-window-horizontally) + (other-window 1) + ;;(switch-to-buffer (concat (file-name-sans-extension bufnam) ".pdf")) + (find-file (concat (file-name-sans-extension buffilnam) ".pdf")) + (doc-view-fit-height-to-window) + (doc-view-fit-window-to-page) + (other-window -1) + )) + +(defun my-view-gnuplot () + "Three windows. +On the right side a *Shell* buffer with optionally +`virtual-auto-fill-mode' active and an Image mode buffer." + (interactive) + + (save-excursion + (let (output-file-name) ;; get figure output name + (goto-char (point-min)) + (when (re-search-forward "set output .*" nil t) + ;; TODO: search text in between set output '...' then I do not + ;; need to replace / remove part of the match string. + (setq output-file-name (match-string 0)) + (setq output-file-name (string-replace "set output " "" output-file-name)) + (setq output-file-name (substring output-file-name 1 -1))) + ;;(message "%s" output-file-name) + + (delete-other-windows) + + (split-window-horizontally (truncate (* 0.6 (window-body-width)))) + (other-window 1) + (if output-file-name + ;;(switch-to-buffer output-file-name) + (find-file output-file-name) + ;;(switch-to-buffer "*scratch*") + (switch-to-buffer " *image*")) + ;;(when (fboundp 'virtual-auto-fill-mode) (virtual-auto-fill-mode)) + + (split-window-vertically) ;; both are shell buffers now. + (switch-to-buffer "*shell*") + (shell) + ;;(when (fboundp 'virtual-auto-fill-mode) (virtual-auto-fill-mode)) + + (other-window -1)))) + +(provide 'my) +;;; my.el ends here diff --git a/settings/general-settings.el b/settings/general-settings.el index 999a63d3..3d5c1047 100644 --- a/settings/general-settings.el +++ b/settings/general-settings.el @@ -648,8 +648,10 @@ with a drive letter and a colon.") (easy-menu-define my-view-menu nil "My Views Menu" '("Views" ["ELisp" my-view-elisp :help "my-view-elisp"] - ["Python" my-view-python :help "my-view-python"] + ["Gnuplot" my-view-gnuplot :help "my-view-gnuplot"] ["Org PDF" my-view-org-pdf :help "my-view-org-pdf"] + ["Python" my-view-python :help "my-view-python"] + ["Shell" my-view-shell :help "my-view-shell"] )) (easy-menu-add my-view-menu nil) (easy-menu-add-item nil '("My") my-view-menu) diff --git a/settings/gui-settings.el b/settings/gui-settings.el index d118d007..031b42d0 100644 --- a/settings/gui-settings.el +++ b/settings/gui-settings.el @@ -92,6 +92,55 @@ ) ) +(use-package tab-bar + :config + (tab-bar-mode) + (tab-bar-rename-tab "Default") + (defun my-tab-view-elisp () + (if (tab-bar--tab-index-by-name "ELisp IDE") + (tab-bar-switch-to-tab "ELisp IDE") + (tab-bar-new-tab) + (tab-bar-rename-tab "ELisp IDE") + (switch-to-buffer "*scratch*") + (my-view-elisp))) + (defun my-tab-view-python () + (if (tab-bar--tab-index-by-name "Python IDE") + (tab-bar-switch-to-tab "Python IDE") + (tab-bar-new-tab) + (tab-bar-rename-tab "Python IDE") + (if (get-buffer "*scratch-python*") + (switch-to-buffer "*scratch-python*") + (switch-to-buffer "*scratch-python*") + (insert "#!/usr/bin/env python\n") + (insert "\"\"\"\n") + (insert "\"\"\"\n")) + (python-mode) + (my-view-python))) + (defun my-tab-view-shell () + (if (tab-bar--tab-index-by-name "Shell IDE") + (tab-bar-switch-to-tab "Shell IDE") + (tab-bar-new-tab) + (tab-bar-rename-tab "Shell IDE") + (switch-to-buffer "*scratch-shell*") + (shell-script-mode) + (my-view-shell))) + (defun my-tab-view-org-pdf () + (if (tab-bar--tab-index-by-name "Org PDF") + (tab-bar-switch-to-tab "Org PDF") + (tab-bar-new-tab) + (tab-bar-rename-tab "Org PDF") + (switch-to-buffer "*scratch-org*") + (org-mode) + (my-view-org-pdf))) + (defun my-tab-view-gnuplot () + (if (tab-bar--tab-index-by-name "Gnuplot IDE") + (tab-bar-switch-to-tab "Gnuplot IDE") + (tab-bar-new-tab) + (tab-bar-rename-tab "Gnuplot IDE") + (switch-to-buffer "*scratch-gnuplot*") + (gnuplot-mode) + (my-view-gnuplot)))) + (use-package awesome-tray :defer 0.2 :config @@ -170,9 +219,15 @@ `(( ;; views ("" "Custom Views:" "custom views" nil default "" "") (,(all-the-icons-fileicon "elisp" :height 1.0 :v-adjust -0.1) - "ELisp" "my-view-elisp" (lambda (&rest _) (my-view-elisp))) + "ELisp" "my-view-elisp" (lambda (&rest _) (my-tab-view-elisp))) (,(all-the-icons-alltheicon "python" :height 1.0 :v-adjust 0.0) - "Python" "my-view-python" (lambda (&rest _) (my-view-python))) + "Python" "my-view-python" (lambda (&rest _) (my-tab-view-python))) + (,(all-the-icons-alltheicon "script" :height 1.0 :v-adjust 0.0) + "Shell" "my-view-shell" (lambda (&rest _) (my-tab-view-shell))) + (,(all-the-icons-octicon "file-media" :height 1.0 :v-adjust 0.0) + "Gnuplot" "my-view-gnuplot" (lambda (&rest _) (my-tab-view-gnuplot))) + (,(all-the-icons-octicon "file-pdf" :height 1.0 :v-adjust 0.0) + "Org PDF" "my-view-org-pdf" (lambda (&rest _) (my-tab-view-org-pdf))) ) ( ;; major modes ("" "Major Modes:" "major modes" nil default "" "") diff --git a/settings/my-settings.el b/settings/my-settings.el index 55069bbf..7392345b 100644 --- a/settings/my-settings.el +++ b/settings/my-settings.el @@ -2,11 +2,11 @@ ;;; Commentary: ;;; Code: (use-package my + :load-path (lambda() (concat user-emacs-directory "lisp/my")) :config (with-eval-after-load 'org (add-hook 'org-mode-hook 'my-org-link-color-hook) - (add-hook 'org-ctrl-c-ctrl-c-hook 'my-org-table-cell-color-attr)) - ) + (add-hook 'org-ctrl-c-ctrl-c-hook 'my-org-table-cell-color-attr))) (provide 'my-settings) ;;; my-settings.el ends here diff --git a/settings/org-settings.el b/settings/org-settings.el index 145234b8..05ece066 100644 --- a/settings/org-settings.el +++ b/settings/org-settings.el @@ -1,15 +1,102 @@ ;;; org-settings.el --- Org settings -*- lexical-binding: t -*- -;;; Commentary: +;; Package-Requires: ((emacs) (org-mode) (org-bullets) (org-cliplink)) + +;; This file is not part of GNU Emacs. + ;; direct LaTeX (not org) ;; hyphen via AUCTeX (not installed) ;; https://tex.stackexchange.com/questions/282448/why-does-emacs-or-auctex-turns-into -;; Requirements: -;; org-mode https://orgmode.org/ -;; org-bullets -;; org-cliplink https://melpa.org/#/org-cliplink +;;; Commentary: +;; * Overview of modes and commands +;; -------------------------------- +;; ** Export `ox-reveal' +;; --------------------- +;; (org-export-get-all-options 'reveal) +;; +;; *** KEYWORDs +;; ------------ +;; *Note*: Using an option which is also set in the configuration will +;; overwrite it. +;; +;; #+REVEAL_ROOT: +;; - path to reveal.js root directory, can be used once +;; - is defined in the configuration, see `org-reveal-root' +;; +;; #+REVEAL_EXTRA_CSS: +;; - path to css file, can be used multiple times +;; - is defined in the configuration, see `org-reveal-extra-css' +;; +;; #+REVEAL_POSTAMBLE: +;; - postamble content, can be used once +;; - is defined in the configuration, see `org-reveal-postamble' +;; +;; #+REVEAL_HLEVEL: +;; - can be configured, see `org-reveal-hlevel' +;; +;; #+REVEAL: split +;; #+REVEAL: split:t +;; +;; #+REVEAL_THEME: +;; +;; #+OPTIONS: reveal_title_slide:auto|"string"|nil +;; #+REVEAL_TITLE_SLIDE: +;; - path to css file, can be used multiple times +;; - can be configured, see `org-reveal-title-slide' +;; +;; #+REVEAL_TITLE_SLIDE_BACKGROUND: #123456|rgb(0,0,0)|./image/path.jpg +;; #+REVEAL_TITLE_SLIDE_BACKGROUND_SIZE: 200px +;; #+REVEAL_TITLE_SLIDE_BACKGROUND_REPEAT: repeat +;; #+REVEAL_TITLE_SLIDE_BACKGROUND_OPACITY: 0.2 +;; +;; #+REVEAL_TOC_SLIDE_BACKGROUND: #123456|rgb(0,0,0)|./image/path.jpg +;; #+REVEAL_TOC_SLIDE_BACKGROUND_SIZE: 200px +;; #+REVEAL_TOC_SLIDE_BACKGROUND_REPEAT: repeat +;; #+REVEAL_TOC_SLIDE_BACKGROUND_OPACITY: 0.2 +;; +;; #+REVEAL_DEFAULT_SLIDE_BACKGROUND: #123456|rgb(0,0,0)|./image/path.jpg +;; #+REVEAL_DEFAULT_SLIDE_BACKGROUND_SIZE: 200px +;; #+REVEAL_DEFAULT_SLIDE_BACKGROUND_POSITION: +;; #+REVEAL_DEFAULT_SLIDE_BACKGROUND_REPEAT: repeat +;; #+REVEAL_DEFAULT_SLIDE_BACKGROUND_TRANSITION: +;; +;; #+OPTIONS: reveal_width: org-reveal-width +;; #+OPTIONS: reveal_height: org-reveal-height +;; #+REVEAL_MARGIN: org-reveal-margin +;; #+REVEAL_MIN_SCALE: org-reveal-min-scale +;; #+REVEAL_MAX_SCALE: org-reveal-max-scale +;; +;; #+REVEAL_INIT_OPTIONS: slideNumber:true|“h.v”|“h/v”|“c”|“c/t” +;; +;; #+REVEAL_SLIDE_HEADER: css class slide-header +;; #+REVEAL_SLIDE_FOOTER: css class slide-footer +;; #+OPTIONS: reveal_global_header:t reveal_global_footer:t +;; +;; *** Properties +;; -------------- +;; see `org-reveal-slide-section-tag' (org-element-property :xxx headline) +;; :PROPERTIES: +;; :reveal_background: #123456|rgb(0,0,0)|./image/path.jpg +;; :reveal_background_trans: slide +;; :reveal_background_size: 200px +;; :reveal_background_repeat: repeat +;; :reveal_background_opacity: 0.2 +;; :reveal_background_iframe: https://domain.tld +;; :END: +;; +;; *** Variables +;; ------------- +;; - `org-reveal-root' - string +;; - `org-reveal-extra-css' - string - multiple values separated by \n +;; - `org-reveal-postamble' - string - only one line +;; - `org-reveal-single-file' - t|nil +;; - `org-reveal-hlevel' +;; +;; {{(my-list-to-org-table (org-export-get-all-options 'reveal))}} +;; + ;;; Code: (defgroup my-org nil "My org-mode concept mapping" @@ -106,6 +193,42 @@ Example defines (const (expand-file-name "brain" "~/org")) (const "~/Sync/workspace/emacs/org-brain"))) +(defun my-org-commentary () + "View org documentation in `outline-mode'." + (interactive) + (let ((buf "*Org: Commentary*")) + ;; kill buffer if aleady open + (when (buffer-live-p (get-buffer buf)) + (kill-buffer buf)) + ;; Use `finder-commentary' to generate the buffer. + (require 'finder) + (cl-letf (((symbol-function 'finder-summary) #'ignore)) + (finder-commentary "org-settings")) + ;; change commentary text + (let ((inhibit-read-only t)) + ;;(insert "org-settings.el\n\n") + ;; point under headline + (forward-line 1) + (save-excursion + ;; remove --- under headlines + (while (re-search-forward "^-+$" nil :noerror) + (replace-match "")) + ;; replace `xxx' with =xxx= + (goto-char (point-min)) + (while (re-search-forward (rx (and "`" (group (+? anything)) "'")) nil :noerror) + (replace-match (concat "=" (match-string 1) "="))) + ;; find {{xxx}} and eval xxx + (goto-char (point-min)) + (while (re-search-forward (rx (and "{{" (group (+? anything)) "}}")) nil :noerror) + (replace-match (eval (my-eval-string (match-string 1))))) + ;; align all tables + (org-table-map-tables 'org-table-align) + )) + (rename-buffer buf) + ;; Enable `org-mode' and `view-mode' for user convenience. + (org-mode) + (view-mode 1))) + ;; uses the org version from the org ELPA repository instead of the ;; one shipped with emacs. Therefore, any org related code should not ;; be loaded before, otherwise both versions will be loaded and will @@ -1083,5 +1206,6 @@ Suggest the URL title as a description for resource." :config (add-hook 'org-brain-visualize-mode-hook #'org-brain-polymode)) + (provide 'org-settings) ;;; org-settings.el ends here