The filename can be obtained in elisp by calling buffer-file-name
.
The line numbers are trickier in that Emacs in general does not care about line numbers, but only about positions in the buffer. The latter can be obtained by parsing the source code block with org-element-at-point
and then retrieving the positions of the beginning and the end. You can then obtain line numbers by going to those points and using line-number-at-pos
.
One complication is that the beginning is the position in the buffer just before the #
in #+begin_src
but the end can be several lines below the #+end_src
line, so you can infer the beginning line as one more than what line-number-at-pos
gives you for the beginning position, but for the end you'll need to back-up a bit to find the #+end_src
line. At that point, you can infer that the end of the program is at a line number one less than what line-number-at-pos
gives you for that point.
Here's an interactive test using the file above:
* Some header
#+begin_src julia
function foo()
1
end
foo()
#+end_src
some text
* Code
#+begin_src elisp :results drawer
(save-excursion
(goto-char 49)
(let* ((context (org-element-context (org-element-at-point)))
(beg (org-element-property :begin context))
(end (org-element-property :end context))
(filename (buffer-file-name)))
(list filename beg end)))
#+end_src
#+RESULTS:
:results:
(/tmp/foo.org 16 77)
:end:
Executing the elisp code block takes you somewhere inside the Julia code block, parses the code block and returns the filename, beginning position and ending position of the Julia code block, as shown in the results: 16 is the position just before the #
in #+begin_src
of the Julia block; 77 is the position just before the s
of some text
- a couple of lines below the #+end_src
line.
The next iteration of the code block returns a list of the filename and the line numbers. The beginning line number is relatively easy, but the ending line number is a bit more complicated because we need to search backward for the #+end_src
string:
#+begin_src elisp :results drawer
(save-excursion
(goto-char 49)
(let* ((context (org-element-context (org-element-at-point)))
(beg (org-element-property :begin context))
(beg-line (save-excursion
(goto-char beg)
(line-number-at-pos)))
(end (org-element-property :end context))
(end-line (save-excursion
(goto-char end)
(search-backward "#+end_src")
(line-number-at-pos)))
(filename (buffer-file-name)))
(list filename (+ beg-line 1) (- end-line 1))))
#+end_src
#+RESULTS:
:results:
(/tmp/foo.org 4 8)
:end:
The assumptions above are that when the execution function of the block runs, it will be the case that the current buffer is still the buffer of the Org mode file containing the code block, otherwise buffer-file-name
will return the filename of a different buffer (or nil
if there is file associated with that buffer); and that the current position in that buffer is still somewhere inside the code block of interest (wherever point
was when you pressed C-c C-c
), otherwise org-element-at-point
will not parse the code block but something else. Some light testing shows that both of these assumptions are correct, so you should be able to plop the code in the code block (without the surrounding save-excursion
, the initial goto-char
, and the return of the final list, all of which are artifacts of the testing) into your org-babel-execute:julia
function and get the information you want. Just to avoid misunderstanding, this is the code you should use:
(let* ((context (org-element-context (org-element-at-point)))
(beg (org-element-property :begin context))
(beg-line (save-excursion
(goto-char beg)
(line-number-at-pos)))
(end (org-element-property :end context))
(end-line (save-excursion
(goto-char end)
(search-backward "#+end_src")
(line-number-at-pos)))
(filename (buffer-file-name)))
;; you can now use filename, (+ beg-line 1) and (- end-line 1) as you wish...