|
Project Information
Featured
|
An emacs package for interactive debugging and error tracing for ESS. Ess-tracebug is now part of ESS SVN and the documentation below refers to this version. Ess-tracebug in this google.code repository works with version 5.14 or earlier of ESS and is incompatible with ESS SVN,
ActivationChoose a prefix key (for example M-t, or may be M-c): (setq ess-tracebug-prefix "\M-t") Toggle the mode with M-x ess-tracebug. To activate it permanently: (setq ess-use-tracebug t) The suppressed command, which was bound to the prefix key, is automatically rebound to double of the key (i.e. M-t M-t or M-c M-c). In this documentation it is assumed that the prefix key is M-c (prior to integration with ESS this was the default). When 'ess-tracebug' is active, [TB] appears in the mode line of the inferior R window. Manual Installation for Version 5.14 or lower of ESSMake sure that your R version is higher than 2.10. Download the ess-tracebug.el and put it into your emacs load-path. Put the following after (load "ess-site.el") in your .emacs: (require 'ess-tracebug) (add-hook 'ess-post-run-hook 'ess-tracebug) The prefix key is by default M-c. Note on KeysIn the description below, the commands tagged with * are single-key commands, which means that after the initial invocation of the prefix key the subsequent invocations of the command can be executed with a single key. For example if you invoke the command ess-bp-set (sets the breakpoint) with "M-c b" and then repeatedly press `b b ` the breakpoint type will be toggled three times through the list of available breakpoint types. Emacs hint: Pres C-h after partially entered key sequence to view all the available keys starting with that combination. For example M-c C-h shows all the available bindings from ess-tracebug-map. Cheat sheetFor convenience here are all the default ess-tracebug key bindings ("M-c ?"). There are some more in watch mode. * Breakpoints: b . Set bp (repeat to cycle bp type) . `ess-bp-set' B . Set Conditional bp . `ess-bp-set-conditional' k . Kill bp . `ess-bp-kil' K . Kill all bps . `ess-bp-kill-all' t . Toggle bp state . `ess-bp-toggle-state' l . Set bp logger . `ess-bp-set-logger' C-n . Goto next bp . `ess-bp-next' C-p . Goto previous bp . `ess-bp-previous' * General Debugging: ` . Show R Traceback . `ess-show-R-traceback' s . Source current file . `ess-dbg-source-current-file' e . Toggle error action . `ess-dbg-toggle-error-action' d . Flag for debugging . `ess-dbg-flag-for-debuging' u . Unflag for debugging . `ess-dbg-unflag-for-debugging' w . Watch window . `ess-watch' * Interactive Debugging: c . Continue . `ess-dbg-command-c' n . Next step . `ess-dbg-command-n' p . Previous error . `previous-error' q . Quit debugging . `ess-dbg-command-Q' 1..9. Enter recover frame . `ess-dbg-command-digit' 0 . Exit recover (also q,n,c) . `ess-dbg-command-digit' * Input Ring: i . Goto input event marker forwards . `ess-dbg-goto-input-event-marker' I . Goto input event marker backwards . `ess-dbg-goto-input-event-marker' * Misc: ? . Show this help . `ess-tracebug-show-help' C-c . `capitalize-word' Error TracingNavigationEss-tracebug provides compilation-like functionality in inferior-ess buffer. The errors with location references are highlighted like this:
To navigate between errors, you can use usual binding for next/previous-error ("M-g n" , "M-g p"), or more conveniently, bind "M-[" and "M-]" as follows: (define-key ess-mode-map "\M-]" 'next-error) (define-key ess-mode-map "\M-[" 'previous-error) (define-key inferior-ess-mode-map "\M-]" 'next-error-no-select) (define-key inferior-ess-mode-map "\M-[" 'previous-error-no-select) Error navigation scope is limited to the most recent errors located between the last user input mark (indicated by the small arrow) and the end of buffer:
Often ESS eval commands result in a long series of errors, but only the first being the most relevant one. Now you can quickly find the first error by locating the fringe arrow. When files are sourced with incomplete file names (source("my_file.R")), R reports only the file name in the error references. Ess-traceback reconstructs the whole path by using the current directory associated with the current buffer. Usually this is not a problem because all the project files are in the same directory. To make ess-tracebug aware of different directories, customize the variable ess-dbg-search-path: (setq ess-dbg-search-path
'("~/projects/R/project_A" "~/projects/R/project_B"))
Traceback BufferWhenever the traceback is available in R (usually immediately after the error occurred) the [M-c `](ess-show-R-traceback) displays *ess-traceback* compilation-like buffer:
You also might want to have simple keys for navigation to error locations in the *ess-traceback* buffer: (define-key compilation-minor-mode-map [(?n)] 'next-error-no-select) (define-key compilation-minor-mode-map [(?p)] 'previous-error-no-select) Visual DebuggerFor the visual debugging you need to set the breakpoints in your source file and source it either interactively with M-c s key, or directly with source() command. Breakpoints
ess-bp-set is an single-key command and multiple invocation of "b" key cycles through the breakpoint types defined in ess-bp-type-spec-alist. Currently only browser() and recover() types are defined. The recover breakpoint is useful whenever you want to examine the call stack. You can add your own custom breakpoints like this: (nconc ess-bp-type-spec-alist '((my-browser "browser(expr = exists(\"a\") && a>.5)" "My-Br>\n" question-mark font-lock-doc-face))) The above creates a conditional breakpoint which is entered only if the variable "a" is greater than 0.5. The name of the new breakpoint is my-browser, the displayed string is "My-Br", fringe bitmap is question-mark and the font of the breakpoint is font-lock-doc-face. See the documentation for ess-bp-type-spec-alist for more details. Available fringe bitmaps are in the variable fringe-bitmaps. M-c t toggles the active state of the breakpoint, i.e. comment it out. Here is the sample of breakpoint types so far discussed (browser, recover, commented browser and the custom my-browser):
Conditional BreakpointsUse 'M-c B' to set the conditional breackpoint:
Loggers
Loggers are like breakpoints but don't break the execution. They log the returned value of the watched expressions into the variable (a list) with the user provided name:
Debugging
To make it handy in operation, all the debugging commands are single-key commands. All of these commands set the emacs command loop into single-key mode. For example, pressing the sequence "M-c n n n c q" executes three "step" commands, one "continue" command and finally "q" triggering the quit. Ess-tracebug automatically detects when the R session enters the debugger and turns single-key mode on. If you don't like this behavior and prefer to start the navigation manually set ess-dbg-auto-single-key-p to nil. The debugger single-key actions are all defined in a separate ess-debug-easy-map:
Ess-tracebug also detects when the session enters the "recover" state. Pressing a digit produces the same effect as typing it in the terminal followed by RET. Also for convenience, "q","c" and "n" have the same effect as "0" - not to interrupt the debugging flow when the recover breackpoint is used. Flag/Unflag for Debugging
Ess-tracebug uses IDO mechanism (if available) to provide the user with the on the fly debugging and undebugging of functions and methods. Debug 'M-c d' asks the user for the function to debug:
If the selected function is a generic, the signature of the method is requested as well:
The following usual IDO keys are available in the mini-buffer:
Library Matrix has a number of methods and S4 classes defined. Load it and play with the methods library(Matrix) Undebug To unflag the debugged function or traced methods use 'M-c u':
If you don't want to use IDO just set: (setq ess-dbg-use-ido nil) Note: Other completion mechanisms might not be compatible with IDO. Particularly if you are using Icicles, 'ess-dbg-use-ido' will probably have to be set to nil as above. Watch Window
In the watch window you can monitor any valid R expression:
Start with 'M-c w' to see all available commands in the watch window.
The text in the watch window is scaled down by 'text-scale-mode-step' times 'ess-watch-scale-amount'. Customize the latter to adjust the display size of the text. The default is '-1'. (setq ess-watch-scale-amount -2) Whenever the watch buffer already exists, it is displayed during the debugging. To prohibit the display, quit the watch ("q") or just kill the buffer. Note what watched expressions are not lost. They are registered in the R session and will be available on the next invocation of 'M-c w'. By default ess-tracebug tries to split the R process window reasonably. You can control that behavior by customizing 'ess-watch-height-threshold' and 'ess-watch-width-threshold'. See the documentation for those variables. On-error Actions
When ess-tracebug is turned on, mode line for the current process is changed into (iESS [R db - ], where "-" is an indicator of an "on-error" action, and can be by default one of:
To switch between on-error states press 'M-c e', and keep pressing 'e' till the desired action is set. You can add your own custom on-error actions to the ess-dbg-error-action-alist. See also R documentation for options(error=). Work-Flow
The general idea is that the project must be kept separate from the working file (analysis.R, test.R, main.R etc). From the working file you source the project and invoke short code, the interactive debugger starts jumping through the code covering your working buffer. At some point you will probably discover the error, interrupt the debugger and make the correction. Now, pressing "M-c i" gets you to the original invocation point in your working file, and repeated invocation of "i" jump to older points in the input 'S-ring''. At any time, pressing "I" brings you backward through the ring. In short, there are two focals, the "input point" in your analysis.R, from where the action starts and the "debug point", where the error is corrected or some other modifications occur. You can jump between this two with "M-c i" and "M-c I": input event S-ring Input S-ring is a data type, specially designed to meet the specific needs for navigation between important points during the debugging process. It consists of two rings, joint at the top - 'ess-dbg-forward-ring' and 'ess-dbg-backward-ring':
Each time when a debug event occurs and the working buffer is covered, the current position of the point is inserted in the 'forward-ring'. You can return to this positions with "i" key. Whenever user invokes "M-c i" for the first time, the current position is registered in the 'backward-ring'. This makes it easy to return to debugged files or sources with "I" key. Since the rings are connected, you can start moving through one ring, while return and end up in another ring. A fresh invocation of "M-c i" will start from the top again. Note that when moving forward, by repeatedly pressing "i", you can only traverse the forward-ring, and will never end up in the backward ring. To get to the backward ring, you must use "I". CustomizationLook at the customization available in ess-racebug group (M-x customize-group ess-tracebug RET) There are also two normal hooks which you can use to redefine the functionality: ess-tracebug-enter-hook ess-tracebug-exit-hook Use 'add-hook function for that. Miscellaneous enhancementsIt turns out that a couple of useful features, unrelated to debugging or tracing, could be implemented using the functionality provided by ess-tracebug. Replacement of long ' + + + 'If 'inferior-ess-replace-long+' is 't' (default), prompts with more than 3 '+'es are replaced with the value of 'ess-long+replacement'. 'ess-long+replacement' is "+ ... + " and you can customize it to anything you like: (setq ess-long+replacement "+.") or even empty string: (setq ess-long+replacement "") Splitting long R promptsIf 'inferior-ess-split-long-prompt' is 't' (default), ESS commands insert a new line after each execution. For example if you execute several 'C-c C-c's in a row, the prompt will not accumulate in one long line like > + + ... + > + + + > but are split accordingly: > + + ... + > > + + + > Process State IndicatorWhenever you execute time consuming commands a running indicator is displayed in the modeline. The type of indicator is given by 'ess-busy-strings' which is a list of strings to be displayed in sequence (see the doc). By default the indicator is the least obtrusive 'ess--busy-slash' which is a rotating bar. But you can customize it to any of the predefined indicators or define your own: (setq ess-busy-strings ess--busy-B) ;; blinking B letter (setq ess-busy-strings ess--busy-stars) ;; progression stars (setq ess-busy-strings ess--busy-vbars) ;; progression vertical bars (setq ess-busy-strings ess--busy-slash) ;; rotating bar - the default There are cases when technically it is not possible to detect if R is busy. This occurs if time consuming command is not the last in execution sequence: Scripts like Sys.sleep(4)
cat("here\n")
will pass unnoticed if you use invisible evaluation ('ess-eval-visibly-p' set to nil). You have the following alternatives:
With visible evaluation (i.e. commands appear in the inferior buffer), the state of the process is always reliably detected. For more on ESS evaluation, see the official documentation at http://ess.r-project.org/Manual/ess.html#Evaluating-code How It WorksIn this section I will give a brief explanation of how things are implemented. Breakpoints Breakpoints are usual "R" expression inserted literally in the buffer. They are masked as an invisible and intangible text for convenience. Thus, care must be taken of where the breakpoints are positioned. Whenever the usual browser() command is illegal, the breakpoint is illegal as well. For example this positioning would be illegal:
You can build your own breakpoint types inserting arbitrary R expressions. The available breakpoints specifications are defined in ess-bp-type-spec-alist. You can customize the displayed symbol, face and fringe bitmap to use with your custom breakpoints. See the doc for that variable. Interactive Debugger When ess-tracebug mode is turned on, it monitors the output of the R sub-process and searches for specific expressions like "debug at", "debugging in", "Browse" etc. As a function of what is found the corresponding action is executed, particularly if the debugging session is detected and source line references are available the interactive debugger kicks in. The ess-tracebug is fully implemented in emacs and does not rely on R's capabilities. Given that emacs regular expressions are very fast, the overhead of keeping the ess-tracebug mode on is negligible. Redefined functions (ess-eval-region) -> (ess-eval-region2) (ess-eval-linewise) -> (ess-eval-linewise2) (ess-command) -> (ess-command2) (inferior-R-input-sender) -> (inferior-R-input-sender2) Notes
|