Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve handling of starting directory #457

Merged
merged 24 commits into from
Oct 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1536e1a
Disaggregate setqs
lionel- Oct 7, 2017
1079d1f
Clean up comments
lionel- Oct 7, 2017
7565e00
Refactor loop to proper form
lionel- Oct 7, 2017
db73034
Alias `ess-directory` to `ess-default-directory`
lionel- Oct 7, 2017
b78ad41
Refactor ess-get-directory()
lionel- Oct 7, 2017
2dd3d23
Reduce noise in directory prompt
lionel- Oct 7, 2017
3f22ff4
Integrate `ess-r-package-mode` with Emacs projects
lionel- Oct 7, 2017
01e1b3c
Use project-current() for checking default directory
lionel- Oct 7, 2017
36dbbd2
Restore directory silently on reloading
lionel- Oct 7, 2017
9907220
Use `ess-default-directory` instead of `default-directory`
lionel- Oct 7, 2017
581ed38
Better names for directory helpers
lionel- Oct 8, 2017
eb46c8d
Rename `ess-default-directory` to `ess-startup-directory`
lionel- Oct 8, 2017
463aeb7
Proper `defvaralias`
lionel- Oct 10, 2017
115f86c
Move ess--parent-dir() to ess-utils.el
lionel- Oct 21, 2017
5a67ea5
Remove wd setter in ESSR startup as it has moved to inferior startup
lionel- Oct 21, 2017
b736d63
Use ess-r-package-project() to get project info
lionel- Oct 21, 2017
00a490a
Rename `ess-r-package-info` to `ess-r-package--project-cache`
lionel- Oct 21, 2017
fa59522
Simplify package finding functions
lionel- Oct 21, 2017
924ddaa
Add ess-r-package-name()
lionel- Oct 21, 2017
a7277b3
Move news item about source dirs to R features
lionel- Oct 21, 2017
63d07c2
Document new project features in news file
lionel- Oct 21, 2017
2924762
Emacs projects' car contains project type not project name
lionel- Oct 21, 2017
4b2e38e
Remove superfluous items from newfeat
lionel- Oct 29, 2017
5a7fb1c
Prefer the `tests` directory over package roots
lionel- Oct 29, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions doc/newfeat.texi
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@
Changes and New Features in 17.05:
@itemize @bullet

@item Lookup for references in inferior buffers has been improved.
New variable @code{ess-r-package-source-roots} contains package
sub-directories which are searched recursively during the file lookup
point. Directories in @code{ess-tracebug-search-path} are now also
searched recursively.

@item The ESS initialisation process has been streamlined. You can now
load the R and Stata modes independently from the rest of ESS. Just put
@code{(require 'ess-r-mode)} or @code{(require 'ess-stata-mode)} in your
Expand All @@ -28,9 +22,30 @@ from capturing the cursor.
@item @ESS{[R]}: New command @code{ess-r-package-use-dir}. It sets the
working directory of the current process to the current package directory.

@item @ESS{[R]}: Launching or reloading R from a package file now sets
the working directory to the package path. You can now launch R from
files within @code{R/} or @code{src/} without worrying about the wd.
@item @ESS{[R]}: Launching R from a package file now recognises the package
root as the likely startup directory for R. If
@code{ess-ask-for-ess-directory} is non-nil, ESS prompts with the
package root as default selection. Otherwise the working directory is
automatically set to the package root.

An exception is made when you are opening a new process from the
@code{tests} folder. Since @code{R CMD check} sets the working directory
to that folder when executing test files, this folder is preferred over
the package root.

The mechanism for selecting a directory is a bit more general if you are
using Emacs 25.1 or older. On those recent Emacsen R packages are now
recognised as Emacs projects and ESS queries Emacs projects to get the
default startup directory. This means that any git or subversion
directory will be recognised as project root even if it is not an R
package (and in fact regardless of language or dialect).

@item @ESS{[R]} Lookup for references in inferior buffers has been
improved. New variable @code{ess-r-package-source-roots} contains
package sub-directories which are searched recursively during the file
lookup point. Directories in @code{ess-tracebug-search-path} are now
also searched recursively.

@end itemize


Expand Down
3 changes: 2 additions & 1 deletion lisp/ess-custom.el
Original file line number Diff line number Diff line change
Expand Up @@ -337,12 +337,13 @@ a workspace."
:group 'ess
:type '(choice (const nil) function))

(defcustom ess-directory nil
(defcustom ess-startup-directory nil
"The directory ESS is run from. It must end in a slash.
Provided as a default if `ess-ask-for-ess-directory' is non-nil.
A nil value means use the current buffer's default directory."
:group 'ess
:type '(choice (const nil) directory))
(defvaralias 'ess-directory 'ess-startup-directory)

(defcustom ess-history-directory nil
"Directory to pick up `ess-history-file' from.
Expand Down
144 changes: 78 additions & 66 deletions lisp/ess-inf.el
Original file line number Diff line number Diff line change
Expand Up @@ -116,25 +116,17 @@ Alternatively, it can appear in its own frame if
(format "(inf-ess 1): lang=%s, dialect=%s, tmp-dialect=%s, buf=%s\n"
ess-language ess-dialect temp-ess-dialect (current-buffer)))
(let* ((process-environment process-environment)
(defdir (or (and ess-directory-function (funcall ess-directory-function))
ess-directory default-directory))

;; Use temp-ess-dialect if not R, R program name otherwise
(temp-dialect (if ess-use-inferior-program-name-in-buffer-name ;VS[23-02-2013]: fixme: this should not be here
(if (string-equal temp-ess-dialect "R")
inferior-ess-r-program-name
temp-ess-dialect) ; use temp-ess-dialect
; if not R, R program name
; otherwise.
temp-ess-dialect)
temp-ess-dialect))
(temp-lang temp-ess-lang)
(procname (let ((ntry 0) ;; find the next non-existent process N (*R:N*)
(done nil))
(while (not done)
(setq ntry (1+ ntry)
done (not
(get-process (ess-proc-name
ntry
temp-dialect)))))
;; Find the next non-existent process N (*R:N*)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much nicer. I am now amazed that I could write that beast :/.

(procname (let ((ntry 1))
(while (get-process (ess-proc-name ntry temp-dialect))
(setq ntry (1+ ntry)))
(ess-proc-name ntry temp-dialect)))
(buf-name-str (funcall ess-gen-proc-buffer-name-function procname))
startdir buf method)
Expand All @@ -147,53 +139,44 @@ Alternatively, it can appear in its own frame if
;; 1) try to use current buffer, if inferior-ess-mode but no process
((and (not (comint-check-proc (current-buffer)))
(eq major-mode 'inferior-ess-mode))
(setq startdir (if ess-ask-for-ess-directory
(ess-get-directory defdir temp-dialect procname)
defdir)
buf (current-buffer)
;; don't change existing buffer name in this case; It is very
;; commong to restart the process in the same buffer.
buf-name-str (buffer-name)
method 1))
(setq startdir (inferior-ess--maybe-prompt-startup-directory procname temp-dialect))
(setq buf (current-buffer))
;; don't change existing buffer name in this case; It is very
;; commong to restart the process in the same buffer.
(setq buf-name-str (buffer-name))
(setq method 1))

;; 2) Take the *R:N* buffer if already exists (and contains dead proc!)
;; fixme: buffer name might have been changed, iterate over all
;; inferior-ess buffers
((get-buffer buf-name-str)
(setq buf (get-buffer buf-name-str)
method 2))
(setq buf (get-buffer buf-name-str))
(setq method 2))

;; 3) Pick up a transcript file or create a new buffer
(t
(setq startdir (if ess-ask-for-ess-directory
(ess-get-directory defdir temp-dialect procname)
defdir)
buf (if ess-ask-about-transfile
(let ((transfilename (read-file-name "Use transcript file (default none):"
startdir "")))
(if (string= transfilename "")
(get-buffer-create buf-name-str)
(find-file-noselect (expand-file-name transfilename))))
(get-buffer-create buf-name-str))
method 3)))
(setq startdir (inferior-ess--maybe-prompt-startup-directory procname temp-dialect))
(setq buf (if ess-ask-about-transfile
(let ((transfilename (read-file-name "Use transcript file (default none):"
startdir "")))
(if (string= transfilename "")
(get-buffer-create buf-name-str)
(find-file-noselect (expand-file-name transfilename))))
(get-buffer-create buf-name-str)))
(setq method 3)))

(ess-write-to-dribble-buffer
(format "(inf-ess 2.0) Method #%d start=%s buf=%s\n" method startdir buf))

(set-buffer buf)
;; Now that we have the buffer, set buffer-local variables.
(ess-setq-vars-local ess-customize-alist) ; buf)
(set-buffer buf)
(ess-setq-vars-local ess-customize-alist)

;; Write out debug info
(ess-write-to-dribble-buffer
(format "(inf-ess 2.1): ess-language=%s, ess-dialect=%s buf=%s \n"
ess-language ess-dialect (current-buffer)))

;; initialize.
(if startdir (setq default-directory startdir))

;; the following was part of ess-multi;

(when startdir (setq default-directory startdir))
(let* ((ess-directory (or startdir
ess-directory))
(infargs (or ess-start-args
Expand Down Expand Up @@ -591,21 +574,48 @@ This marks the process with a message, at a particular time point."

;;*;; Requester functions called at startup

(defun ess-get-directory (default dialect procname)
(let ((prog-version (cond ((string= dialect "R")
(concat ", " inferior-R-version)) ; notably for the R-X.Y versions
(inferior-ess-program
(concat ", " inferior-ess-program ))
(t ""))))
(ess-prompt-for-directory
(directory-file-name default)
(format "ESS (*%s*%s) starting data directory? "
procname prog-version)
;; (format "ESS [%s {%s(%s)}: '%s'] starting data directory? "
;; ;;FIXME: maybe rather tmp-dialect (+ evt drop ess-language?)?
;; procname ess-language ess-dialect prog-version)
)))

;; FIXME EMACS 25.1:
;; Deprecate `ess-directory-function' in favour of `project-find-functions'?
(defun inferior-ess--get-startup-directory ()
(let ((dir (or (and (fboundp 'project-current)
(cdr (project-current)))
(and ess-directory-function
(funcall ess-directory-function))
ess-startup-directory
default-directory)))
(directory-file-name dir)))

;; FIXME: Move all that R stuff elsewhere
(defun inferior-ess-r--adjust-startup-directory (dir dialect)
(if (string= dialect "R")
(let* ((project-dir (cdr (ess-r-package-project)))
(tests-dir (expand-file-name (file-name-as-directory "tests")
project-dir)))
;; Prefer the `tests' directory but only if the package
;; directory was selected in the first place
(if (and project-dir
(string= project-dir dir)
(string= default-directory tests-dir))
tests-dir
dir))
dir))

(defun inferior-ess--maybe-prompt-startup-directory (procname dialect)
(let ((default-dir (inferior-ess-r--adjust-startup-directory
(inferior-ess--get-startup-directory)
dialect)))
(if ess-ask-for-ess-directory
(let* ((prog (cond ((string= dialect "R")
;; Includes R-X.Y versions
(concat ", " inferior-R-version))
(inferior-ess-program
(concat ", " inferior-ess-program ))
(t "")))
(prompt (format "%s starting project directory? "
procname
prog)))
(ess-prompt-for-directory default-dir prompt))
default-dir)))

(defun ess-prompt-for-directory (default prompt)
"`prompt' for a directory, using `default' as the usual."
Expand Down Expand Up @@ -2584,14 +2594,16 @@ before you quit. It is run automatically by \\[ess-quit]."
;; Interrupt early so we can get working directory
(ess-interrupt)
(save-window-excursion
(:override
(let ((dir (ess-get-working-directory))
(ess-ask-for-ess-directory nil)
(proc (ess-get-proc)))
(ess-quit 'no-save)
(inferior-ess--wait-for-exit proc)
(error "Unimplemented for this dialect")
(ess-set-working-directory dir)))))
;; Make sure we don't ask for directory again
;; Use current working directory as default
(let ((project-find-functions nil)
(ess-directory-function nil)
(ess-startup-directory (ess-get-working-directory))
(ess-ask-for-ess-directory nil))
(ess-quit 'no-save)
(inferior-ess--wait-for-exit (ess-get-process))
(:override
(error "Unimplemented for this dialect")))))

(defun inferior-ess--wait-for-exit (proc)
"Wait for process exit.
Expand Down
19 changes: 3 additions & 16 deletions lisp/ess-r-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -595,10 +595,6 @@ Executed in process buffer."
(when inferior-ess-language-start
(ess-eval-linewise inferior-ess-language-start
nil nil nil 'wait-prompt))
;; FIXME Emacs 25.1: Use `when-let'
(let ((pkg-path (cdr (ess-r-package-get-info))))
(when pkg-path
(ess-set-working-directory pkg-path)))
(with-ess-process-buffer nil
(add-hook 'ess-presend-filter-functions 'ess-R-scan-for-library-call nil 'local)
(run-mode-hooks 'ess-r-post-run-hook)))
Expand Down Expand Up @@ -1168,7 +1164,7 @@ attached packages."
'(:eval (let ((env (ess-r-get-evaluation-env)))
(if env
(format " %s"
(propertize (if (equal env (car (ess-r-package-get-info)))
(propertize (if (equal env (ess-r-package-name))
"pkg"
env)
'face 'mode-line-emphasis))
Expand Down Expand Up @@ -1386,17 +1382,8 @@ we flush the cache.")
:group 'ess-R)

(ess-defmethod R inferior-ess-reload (&optional start-args)
(let ((dir (ess-get-working-directory))
(ess-ask-for-ess-directory nil)
(proc (ess-get-process)))
(with-ess-process-buffer nil
(ess-quit 'no-save)
(inferior-ess--wait-for-exit proc)
(R start-args)
(run-hooks 'inferior-ess-r-reload-hook))
;; If we are in a package the working directory is already set
(unless (cdr ess-r-package-info)
(ess-set-working-directory dir))))
(R start-args)
(run-hooks 'inferior-ess-r-reload-hook))

(defun inferior-ess-r-force (&optional prompt force no-autostart ask-if-1)
(setq ess-dialect "R")
Expand Down
Loading