Re: [O] lisp: scoping vars in repetitive defuns
On Tue, Sep 17, 2019 at 8:46 AM John Kitchin wrote: > I don't totally understand what you are trying to do here. > I think the explanation was a little unclear! > If this were Python, it sounds like you want some kind of class that > stores a variable and reuses it several different functions? Something kind > of similar to that in elisp is a closure, which is like what you described. > For example, here, we define a variable a, and then define two functions > that use it persistently. > > > I think you can wrap this in a macro to make new functions, e.g. > > #+BEGIN_SRC emacs-lisp > (defmacro f-maker (a) > `(lexical-let ((a ,a)) > (defun f1 (x) >(* a x)) > > (defun f2 (x) >(+ a x > > (f-maker 3) > > (list (f1 2) (f2 2)) > #+END_SRC > > #+RESULTS: > | 6 | 5 | > > This is basically what I want, except it turned out to be easier to just wrap the body forms in a let *within*the function. THis is what I came up with: #+BEGIN_SRC emacs-lisp (defmacro dh-factory (name body docstring) "A helper macro that sets up the environment to simplify defining multiple functions with the same environment variables. NAME will bcome the functin name, BODY is a list containing the lisp forms specific to the function, and DOCSTRING is an optional ... docstring. NAME wil lbe wrapped in a `let` statement setting all the remelvant variables." `(lexical-let (()) (defun ,name ,() ,docstring (interactive) (let* ((gh (org-entry-get (point) "GITHUB")) (base (org-entry-get (point) "ORG_LMS_ASSIGNMENT_DIRECTORY")) (findFiles `( ,(concat "Reflection/" gh ".md") ,(concat "students/" gh ".json"))) (browseFiles `( "index.html" )) (testOutput "TestResults/testresults.html") (testCommand "MARKING=instructor npm test")) ,@body (dh-factory dh-find-files ((dolist (f findFiles) (message "%s" (concat base "/" f)) (if (file-exists-p (concat base "/" f)) (find-file-other-window (concat base "/" f) ) (message "File %s does not exist, not opening." f))) ) "Open gradable files in Emacs windows") (dh-factory dh-view ((loop for f in browseFiles do (browse-url-of-file (concat base "/" f "open viewable files in browser") ;; this one should really pass a variable to allow different branches! oh well. (dh-factory dh-status ((magit-status base) (let ((currentBranch (shell-command-to-string (format "cd %s && git rev-parse --abbrev-ref HEAD" base) )) (currentCommit (shell-command-to-string (format "cd %s && git rev-parse HEAD" base (magit-stash-worktree (format "Stashed random files from %s after commit %s." currentBranch currentCommit))) (magit-checkout (concat gh "-master"))) "Open a magit-status buffer and check out this student's branch in the repo") (dh-factory dh-tests ((let ((output)) (with-temp-buffer (message (concat "cd " base " ; npm test")) (setq output (shell-command-to-string (concat "cd " base " ; npm test" (message "WELL, sorta made it through: %s" output) (browse-url-of-file (concat base testOutput "Run tests directly from macs and view output") #+END_SRC I quite like it, though it's a bit unwieldy not to have the the source code available for edebug etc. It feels a little like having a namespace; I'm not afraid of polluting the global namespace, but I can use these symbol names throughout the code I'm processing via the factory. I'm not sure it's *all* that much more efficient though... > > There is also a class system you can probably use like this called eieio, > Here is one approach to doing this. > > #+BEGIN_SRC emacs-lisp > (require 'eieio) > > (defclass Grade () > ((:a :initarg :a))) > > (cl-defmethod gf1 ((g Grade) x) > (* (oref g :a) x)) > > (cl-defmethod gf2 ((g Grade) x) > (+ (oref g :a) x)) > > (let ((G (Grade :a 3))) > (list (gf1 G 2) (gf2 G 2))) > #+END_SRC > > #+RESULTS: > | 6 | 5 | > > I would love to learn to use eieio but it feels like a bit of a jump. > > Finally, maybe the simplest thing to do is pass this information in as an > argument, e.g. a plist or alist, or get them from a function that you only > change in one place? > That might have been more sensible but this was pretty fun! Thanks everyone for the help! > On Tue, Sep 17, 2019 at 7:31 AM Matt Price wrote: > >> I have a number of convenience functions define to help me with grading >> assignments. As I go through the semester, i update all of these functions >> modestly so that they'rehelpful for grading the current assignment. >> >> I big chunk of these simple
[O] Bug: Org commit d07d8ff41 breaks square-brace links in recent Emacs. [9.2.6 (release_9.2.6-538-g23113f @ /home/kfogel/src/org-mode/lisp/)]
Hi. It appears that commit d07d8ff4163 in Org Mode causes square-brace-enclosed links to display incorrectly. The buggy behavior is simple to describe: if you write a link like this [[URL][LINK-TEXT]] then URL will be displayed instead of LINK-TEXT (and LINK-TEXT goes unused: URL is still also given as the underlying link). I haven't debugged this, but it seems to be caused by this commit in Org Mode: > commit d07d8ff416373e5a4f2d91ed1d7f9cb3a80b8439 > Author: Max Mouratov > AuthorDate: Thu Aug 29 22:48:22 2019 +0500 > Commit: Nicolas Goaziou > CommitDate: Mon Sep 16 18:55:04 2019 +0200 > > Prevent loss of `re-search-forward' results > > * org.el (org-activate-links): `match-beginning' and `match-end` should > be called shortly after `re-search-forward'. Otherwise, they may return > values corresponding to a different invocation of `re-search-forward'. > > TINYCHANGE > > M lisp/org.el Here's how to verify 1) Revert just commit d07d8ff41 in your Org Mode source tree 2) 'make' 3) 'make autoloads' 4) Restart Emacs With that commit reverted, links behave correctly. When I restored the commit (and rebuilt, etc), links behaved incorrectly again. This is all with the latest 'master' branch of Emacs (commit 746b20c237), with latest development Org Mode (commit 23113feb9a, which is only one commit beyond the suspect commit). Best regards, -Karl Emacs : GNU Emacs 27.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.11) of 2019-09-17 Package: Org mode version 9.2.6 (release_9.2.6-538-g23113f @ /home/kfogel/src/org-mode/lisp/)
[O] bug with emacs 26.3 and hyperlinks
Hello, today I upgraded to emacs 26.3. and links don't show up correct anymore with org-mode from git. The link is shown not the description. Steps to reproduce: =test.org=: #+begin_src org [[http://www.google.com][A Test link]] #+end_src : emacs -Q --find-file="test.org" All links are shown as described above. =git bisect= shows following commit as root cause: Author: Max Mouratov Date: Thu Aug 29 22:48:22 2019 +0500 Prevent loss of `re-search-forward' results * org.el (org-activate-links): `match-beginning' and `match-end` should be called shortly after `re-search-forward'. Otherwise, they may return values corresponding to a different invocation of `re-search-forward'. TINYCHANGE :04 04 f3bac3041e71bff7b3c0ca2495bd629d8f3f2833 634c8baa25f1ad4f3620d9ad26995ac17c26de6b M lisp "GNU Emacs 26.3 (build 2, x86_64-pc-linux-gnu, GTK+ Version 3.22.30) of 2019-09-16" Org mode version 9.2.6 (release_9.2.6-541-g46767c @ /home/thommy/git-emacs/org-mode/lisp/) Thanks for looking into this. -- Thomas
Re: [O] lisp: scoping vars in repetitive defuns
Matt Price writes: > I have a number of convenience functions define to help me with grading > assignments. As I go through the semester, i update all of these functions > modestly so that they'rehelpful for grading the current > assignment. > > I big chunk of these simple functions is taken up just declaring variables > with (let (())) forms. Each function uses some ofhte same variables, e.g: > > (defun dh-find-files () > (interactive) > (let* ((base (org-entry-get (point) "ORG_LMS_ASSIGNMENT_DIRECTORY")) > (gh (org-entry-get (point) "GITHUB")) > (f2o `( ,(concat "Reflection/" gh ".md") ,(concat "students/" gh > ".json" "01/index.html" "02/index.html" "03/style.css" "04/style.css" > (message "%s" f2o) > ;; make more flexible for resubmits > (shell-command (concat "cd " base " && git checkout " gh "-master")) > (dolist (x f2o) > (if (file-exists-p (concat base "/" x)) > (find-file-other-window (concat base "/" x) ) > (message "File %s does not exist, not opening." x) > > (defun dh-tests () > (interactive) > (let* ((base (org-entry-get (point) "ORG_LMS_ASSIGNMENT_DIRECTORY" )) > (gh (org-entry-get (point) "GITHUB"))) > (with-temp-buffer (shell-command (concat "cd " base " && npm test") t)) > ;; the "t" lets us suppress buffer > (browse-url-of-file (concat base "/TestResults/testresults.html")) > ;; (dh-mocha-run) > > )) > > -- > > This semester I changed some elements of my workflow and I had to update all > the (org-entry-get) calls to new values. It makes me think the code is less > maintainable than it could be. I would like to do > something like this: > > (lexical-let ((base `(org-entry-get (point) "ORG_LMS_ASSIGNMENT_DIRECTORY") > (gh `(org-entry-get (point) "GITHUB")) ) > (defun dh-find-files () > (with-temp-buffer (shell-command (concat "cd " base " && npm test") t)) ;; > the "t" lets us suppress buffer > (browse-url-of-file (concat base "/TestResults/testresults.html") > > Obviously it doesn't work this way. But is there any way to set macros like > this to be expanded later inside a function definition? I feel certain there > must be... Are you overthinking this perhaps? Wouldn't variables work? Like e.g.: (defvar org-lms-assignment-dir-prop "ORG_LMS_ASSIGNMENT_DIRECTORY") (defun dh-find-files() ... (let ((base (org-entry-get (point) org-lms-assignment-dir) ... and then you only have one place to change it? It's quite possible of course that I'm misunderstanding what you are looking for. > > Thanks, > > Matt > -- Nick "There are only two hard problems in computer science: cache invalidation, naming things, and off-by-one errors." -Martin Fowler
Re: [O] lisp: scoping vars in repetitive defuns
I don't totally understand what you are trying to do here. If this were Python, it sounds like you want some kind of class that stores a variable and reuses it several different functions? Something kind of similar to that in elisp is a closure, which is like what you described. For example, here, we define a variable a, and then define two functions that use it persistently. #+BEGIN_SRC emacs-lisp (lexical-let ((a 5)) (defun f1 (x) (* a x)) (defun f2 (x) (+ a x))) (list (f1 2) (f2 2)) #+END_SRC #+RESULTS: | 10 | 7 | I think you can wrap this in a macro to make new functions, e.g. #+BEGIN_SRC emacs-lisp (defmacro f-maker (a) `(lexical-let ((a ,a)) (defun f1 (x) (* a x)) (defun f2 (x) (+ a x (f-maker 3) (list (f1 2) (f2 2)) #+END_SRC #+RESULTS: | 6 | 5 | There is also a class system you can probably use like this called eieio, Here is one approach to doing this. #+BEGIN_SRC emacs-lisp (require 'eieio) (defclass Grade () ((:a :initarg :a))) (cl-defmethod gf1 ((g Grade) x) (* (oref g :a) x)) (cl-defmethod gf2 ((g Grade) x) (+ (oref g :a) x)) (let ((G (Grade :a 3))) (list (gf1 G 2) (gf2 G 2))) #+END_SRC #+RESULTS: | 6 | 5 | Finally, maybe the simplest thing to do is pass this information in as an argument, e.g. a plist or alist, or get them from a function that you only change in one place? John --- Professor John Kitchin Doherty Hall A207F Department of Chemical Engineering Carnegie Mellon University Pittsburgh, PA 15213 412-268-7803 @johnkitchin http://kitchingroup.cheme.cmu.edu On Tue, Sep 17, 2019 at 7:31 AM Matt Price wrote: > I have a number of convenience functions define to help me with grading > assignments. As I go through the semester, i update all of these functions > modestly so that they'rehelpful for grading the current assignment. > > I big chunk of these simple functions is taken up just declaring variables > with (let (())) forms. Each function uses some ofhte same variables, e.g: > > (defun dh-find-files () > (interactive) > (let* ((base (org-entry-get (point) "ORG_LMS_ASSIGNMENT_DIRECTORY")) > (gh (org-entry-get (point) "GITHUB")) > (f2o `( ,(concat "Reflection/" gh ".md") ,(concat "students/" gh > ".json" "01/index.html" "02/index.html" "03/style.css" > "04/style.css" > (message "%s" f2o) > ;; make more flexible for resubmits > (shell-command (concat "cd " base " && git checkout " gh "-master")) > (dolist (x f2o) > (if (file-exists-p (concat base "/" x)) > (find-file-other-window (concat base "/" x) ) > (message "File %s does not exist, not opening." x) > > (defun dh-tests () > (interactive) > (let* ((base (org-entry-get (point) "ORG_LMS_ASSIGNMENT_DIRECTORY" )) > (gh (org-entry-get (point) "GITHUB"))) > (with-temp-buffer (shell-command (concat "cd " base " && npm test") > t)) ;; the "t" lets us suppress buffer > (browse-url-of-file (concat base "/TestResults/testresults.html")) > ;; (dh-mocha-run) > > )) > > -- > > This semester I changed some elements of my workflow and I had to update > all the (org-entry-get) calls to new values. It makes me think the code is > less maintainable than it could be. I would like to do something like this: > > (lexical-let ((base `(org-entry-get (point) "ORG_LMS_ASSIGNMENT_DIRECTORY") >(gh `(org-entry-get (point) "GITHUB")) ) > (defun dh-find-files () > (with-temp-buffer (shell-command (concat "cd " base " && npm test") t)) ;; > the "t" lets us suppress buffer > (browse-url-of-file (concat base "/TestResults/testresults.html") > > > Obviously it doesn't work this way. But is there any way to set macros > like this to be expanded later inside a function definition? I feel certain > there must be... > > Thanks, > > Matt >
[O] lisp: scoping vars in repetitive defuns
I have a number of convenience functions define to help me with grading assignments. As I go through the semester, i update all of these functions modestly so that they'rehelpful for grading the current assignment. I big chunk of these simple functions is taken up just declaring variables with (let (())) forms. Each function uses some ofhte same variables, e.g: (defun dh-find-files () (interactive) (let* ((base (org-entry-get (point) "ORG_LMS_ASSIGNMENT_DIRECTORY")) (gh (org-entry-get (point) "GITHUB")) (f2o `( ,(concat "Reflection/" gh ".md") ,(concat "students/" gh ".json" "01/index.html" "02/index.html" "03/style.css" "04/style.css" (message "%s" f2o) ;; make more flexible for resubmits (shell-command (concat "cd " base " && git checkout " gh "-master")) (dolist (x f2o) (if (file-exists-p (concat base "/" x)) (find-file-other-window (concat base "/" x) ) (message "File %s does not exist, not opening." x) (defun dh-tests () (interactive) (let* ((base (org-entry-get (point) "ORG_LMS_ASSIGNMENT_DIRECTORY" )) (gh (org-entry-get (point) "GITHUB"))) (with-temp-buffer (shell-command (concat "cd " base " && npm test") t)) ;; the "t" lets us suppress buffer (browse-url-of-file (concat base "/TestResults/testresults.html")) ;; (dh-mocha-run) )) -- This semester I changed some elements of my workflow and I had to update all the (org-entry-get) calls to new values. It makes me think the code is less maintainable than it could be. I would like to do something like this: (lexical-let ((base `(org-entry-get (point) "ORG_LMS_ASSIGNMENT_DIRECTORY") (gh `(org-entry-get (point) "GITHUB")) ) (defun dh-find-files () (with-temp-buffer (shell-command (concat "cd " base " && npm test") t)) ;; the "t" lets us suppress buffer (browse-url-of-file (concat base "/TestResults/testresults.html") Obviously it doesn't work this way. But is there any way to set macros like this to be expanded later inside a function definition? I feel certain there must be... Thanks, Matt
Re: [O] Import CSV file, remove columns, print table
Hi John, Thanks, that's great. To get horizontal lines between each participant so that there is a nice box for the signatures I tried return tabulate.tabulate(sorted_results, tablefmt='grid') This works, but then the #+ATTR_LaTeX: :environment longtable :align |r|l|l|p{8cm}| seems to be ignored. Is it possible to tweak the output for 'orgtbl' to insert hlines? The other solution of course would be to not use 'tabulate' but generate the table explicitly. Cheers, Loris John Kitchin writes: > Here is another 'source block' solution, this time in python. You > could so something similar in elisp. Here I use the library of babel > approach so you can call it wherever you want. > > #+name: csv > | ID | Name | Titel / Title | Vorname / First Name | Nachname / > Surname | Institution | > | 3 | Carol Carrot | Prof. | Carol| Carrot > | University of Veg | > | 1 | Alice Apple | Fr./Ms. | Alice| Apple > | Universität zum Apfel | > | 2 | Bob Birne| Hr./Mr. | Bob | Birne > | Pear University | > > See https://orgmode.org/worg/org-contrib/babel/library-of-babel.html > > #+name: signature-table > #+BEGIN_SRC python :var data=csv :results value raw > results = [[surname, firstname, ""] for _, _, _, firstname, surname, _ in > data[1:]] > > sorted_results = sorted(results,key=lambda row: row[1]) > > sorted_results = [[i + 1] + result for i, result in enumerate(sorted_results)] > > import tabulate > return tabulate.tabulate(sorted_results, ['#', 'Surname', 'First name', > 'Signature'], tablefmt='orgtbl') > #+END_SRC > > #+call: signature-table(data=csv) > > #+RESULTS: > | # | Surname | First name | Signature | > |---+-++---| > | 1 | Apple | Alice | | > | 2 | Birne | Bob| | > | 3 | Carrot | Carol | | > > --- > Professor John Kitchin > Doherty Hall A207F > Department of Chemical Engineering > Carnegie Mellon University > Pittsburgh, PA 15213 > 412-268-7803 > @johnkitchin > http://kitchingroup.cheme.cmu.edu > > On Mon, Sep 16, 2019 at 8:48 AM Loris Bennett > wrote: > > Hi John, > > Thanks - that's a nicely compact solution, albeit in the category > 'source block' and in a language I'm not very skilled at :-) > > I realise that I have slightly misstated the problem. The ID in the > imported CSV is just a key from the database - I don't need it on the > list of participants. However, it would be nice to number the > participants, who are sorted by surname. > > How would I insert a column which just numbers the row? > > Cheers, > > Loris > > John Kitchin writes: > > > You can do something like this: > > > > #+name: csv > > | ID | Name | Titel / Title | Vorname / First Name | Nachname / > Surname | Institution | > > | 1 | Alice Apple | Fr./Ms. | Alice| Apple > | Universität zum Apfel | > > | 2 | Bob Birne| Hr./Mr. | Bob | Birne > | Pear University | > > | 3 | Carol Carrot | Prof. | Carol| Carrot > | University of Veg | > > > > #+BEGIN_SRC emacs-lisp :var data=csv > > (let ((table (mapcar (lambda (row) (list (nth 0 row) (nth 4 row) (nth 3 > row))) data))) > > (setf (car table) (append (car table) '("Signature"))) > > table) > > #+END_SRC > > > > #+RESULTS: > > | ID | Nachname / Surname | Vorname / First Name | Signature | > > | 1 | Apple | Alice| | > > | 2 | Birne | Bob | | > > | 3 | Carrot | Carol| | > > > > John > > > > --- > > Professor John Kitchin > > Doherty Hall A207F > > Department of Chemical Engineering > > Carnegie Mellon University > > Pittsburgh, PA 15213 > > 412-268-7803 > > @johnkitchin > > http://kitchingroup.cheme.cmu.edu > > > > On Fri, Sep 13, 2019 at 9:36 AM Loris Bennett > wrote: > > > > Hi, > > > > I want to create a list of participants of an event which people can > > sign, so that I can record who actually turned up. > > > > From the registration website I can download a CSV file and import it > > into and org file: > > > > | ID | Name | Titel / Title | Vorname / First Name | Nachname / > Surname | Institution | > > | 1 | Alice Apple | Fr./Ms. | Alice| Apple > | Universität zum Apfel | > > | 2 | Bob Birne| Hr./Mr. | Bob | Birne > | Pear University | > > | 3 | Carol Carrot | Prof. | Carol| Carrot > | University of Veg | > > > > I would like to reduce this to > > > > | ID | Nachname / Surname | Vorname /