Skip to content

sagemath/sage-shell-mode

Repository files navigation

sage-shell-mode

http://melpa.org/packages/sage-shell-mode-badge.svg http://stable.melpa.org/packages/sage-shell-mode-badge.svg https://travis-ci.org/sagemath/sage-shell-mode.svg

Overview

sage-shell-mode is an elisp package and provides an Emacs front end for Sage.

sage-shell-mode provides two main features:

  1. sage-shell-mode to run the Sage terminal inside Emacs.
  2. sage-shell:sage-mode for editing .sage source files and sending their contents directly to the Sage terminal. This major mode is derived from python-mode.

The package supports extensions with auto-complete-sage, helm-sage, anything-sage and ob-sagemath.

Table of Contents

Requirements

  1. GNU Emacs 24.4 later.
  2. Local installation of Sage.
  3. The Emacs package deferred. This will be installed automatically if you follow the guide below.

Installation and Setup

The most convenient is to use the Emacs package manager to install sage-shell-mode from MELPA:

  1. See http://melpa.org/#/getting-started if you do not have a configuration for MELPA.
  2. Install sage-shell-mode by
    • M-x package-refresh-contents
    • M-x package-install RET sage-shell-mode.

    (Alternatively, you can use =use-package= (available from MELPA) for installation and setup).

  1. Configuration.

    Sage internally uses IPython to manage user interaction at the console, Jupyter cell or, in our case, emacs buffer. Due to IPython evolution (governed upstream Sage), this interaction has to be managed differently by sage-shell-mode according to the Ipython version available, itself depending on Sage’s version. This configuration is governed by two customizable variables :

    • sage-shell:use-prompt-toolkit, which must be t for Sage versions >= 7.4.beta0 and < 9.2.beta8, and nil otherwise ;
    • sage-shell:use-simple-prompt, which must be t for Sage versions >= 9.2.beta9, and nil otherwise.

    (Note : Sage 9.2.beta8 is a lost cause ; complain fiercely, then upgrade to something newer…).

    The function sage-shell:set-ipython-version does this automatically, but takes a couple of seconds to execute at startup. Its use is controlled by the custom variable sage-shell:set-ipython-version-on-startup (t by default).

    Similarly, sage-shell:check-ipython-version (controlled by the custom variable sage-shell:check-ipython-version-on-startup) checks that your options are acceptable to your IPython version, and will yell at you (in the *Messages* buffer) if this is not the case.

    By default, both functions are enabled at startup. A (reckless) user of (say) Sage 9.2.beta10 could shave a couple seconds startup time by setting :

    	(custom-set-variables
    	 '(sage-shell:use-prompt-toolkit nil)
    	 '(sage-shell:use-simple-prompt t)
    	 '(sage-shell:set-ipython-version-on-startup nil)
    	 '(sage-shell:check-ipython-version-on-startup nil))
        

    in its init file (or in the :init clause of its sage-shell-mode use-package call).

  2. You can now run Sage inside Emacs by M-x sage-shell:run-sage, if Emacs can find the executable file of Sage.

    If Emacs cannot find the executable file, add the following line to your Emacs init file:

    (setq sage-shell:sage-root "/path/to/sage/root_directory")
        

    And replace /path/to/sage_root_directory by the root directory of Sage, i.e. $SAGE_ROOT. If you do not know the root directory of Sage, evaluate the following code in a Sage terminal:

    import os; print os.environ["SAGE_ROOT"]
        

    Alternatively, instead of setting sage-shell:sage-root, you may set the variable sage-shell:sage-executable.

    (setq sage-shell:sage-executable "/path/to/sage/executable")
        

    Here /path/to/sage/executable is the path of the executable file of Sage. This may be a symbolic link.

Sample configuration

Here is a sample configuration.

;; Run SageMath by M-x run-sage instead of M-x sage-shell:run-sage
(sage-shell:define-alias)

;; Turn on eldoc-mode in Sage terminal and in Sage source files
(add-hook 'sage-shell-mode-hook #'eldoc-mode)
(add-hook 'sage-shell:sage-mode-hook #'eldoc-mode)

Aliases

The official Emacs major mode for Sage used to be sage-mode. To avoid name conflicts with this package, sage-shell-mode prefixes all names with sage-shell.

If you are not using sage-mode at all, you can define more convenient aliases for sage-shell-mode by adding the following to your Emacs init file after the line (require 'sage-shell-mode):

(sage-shell:define-alias)

The following aliases will be defined:

Original nameAlias
sage-shell:run-sagerun-sage
sage-shell:run-new-sagerun-new-sage
sage-shell:sage-modesage-mode
sage-shell:sage-mode-mapsage-mode-map
sage-shell:sage-mode-hooksage-mode-hook

This means e.g. that you can do M-x run-sage to run Sage, instead of M-x sage-shell:run-sage.

Basic Usage

Running a Sage Process

You can start a Sage process by M-x sage-shell:run-sage. If you need to open multiple Sage processes simultaneously, you can start new ones by M-x sage-shell:run-new-sage. You can restart the current process by M-x sage-shell:restart-sage.

CommandAliasDescription
sage-shell:run-sagerun-sageRun a Sage process.
sage-shell:run-new-sagerun-new-sageRun another Sage process.
sage-shell:restart-sageNoneRestart the current Sage process.

The major-mode of the Sage process buffer is sage-shell-mode.

The Sage Process as a terminal

The primary element of sage-shell-mode is interacting with the Sage process you just started. The Sage process buffer communicates directly with a Sage shell in the background and behaves very much like it. You just type and send the command with <Enter>:

sage: 2+2
4
sage: (x^2 + 2*x + 1).factor()
(x + 1)^2
sage:

The buffer behaves like an Emacs shell:

  • M-p or C-up goes through earlier input.
  • Previous input and output is retained earlier in the buffer. You can move around just as usual and e.g. copy from it or search.
  • To exit, you can enter quit at the prompt or type C-d (bound to sage-shell:delchar-or-maybe-eof) at a blank line.

The buffer also behaves much like the Sage terminal:

Tab completion

<Tab> at the prompt completes the current word. It understands all Sage and Python functions currently in scope, and it also completes attributes of objects. If there are multiple possibilities, they are presented in another window.

sage: G = graphs.PetersenGraph()
sage: G.<TAB>
<All methods on G are shown in a new buffer>
sage: G.charp<TAB>
<G.charp is completed uniquely to G.charpoly>

By default, Tab completion uses completion-at-point. Alternatively, you can use pcomplete by adding the following to your Emacs init file:

(setq sage-shell:completion-function 'pcomplete)

You can also use auto-complete, anything or helm for completion. This requires installing those extensions, see Extensions.

? Help

By writing the name of an object at the prompt, followed by ? and then RET, you are shown the documentation of that object:

sage: G = graphs.PetersenGraph()
sage: G.charpoly?
<Documentation is shown in a new Sage Document buffer>

This is identical to running C-c C-h and then typing the name of the object.

?? Source Lookup

If you use ?? instead ? after a Sage object, then the source code for that object will be opened in a new buffer:

sage: G = graphs.PetersenGraph()
sage: G.charpoly??
<The file src/sage/graphs/generic_graph.py is opened at "def characteristic_polynomial(...):">

Most important key-bindings

Key StrokeCommandDescription
RETsage-shell:send-inputEvaluate the expression written at the prompt.
TABsage-shell-tab-commandComplete a partially written word or indent a line.
C-dsage-shell:delchar-or-maybe-eofDelete the next input character. End the Sage process if nothing is input.
C-c C-csage-shell:interrupt-subjobInterrupt the current computation.
M-pcomint-previous-inputGo backward through input history.
M-nsage-shell:next-inputGo forward through input history.
C-c C-osage-shell:delete-outputRemove all output from Sage since last input prompt.
C-c M-osage-shell:clear-current-bufferClear the entire Sage process buffer, leaving just the prompt.
C-c C-lsage-shell:load-fileAsks for a file and loads it into Sage
C-c C-hsage-shell:helpAsk for the name of a Sage object and show its documentation.
? RETsage-shell-help::describe-symbolShow the documentation of the object directly preceding the ?.
?? RETsage-shell:find-source-in-view-modeVisits the source code of the object directly preceding the ??.
C-c osage-shell:list-outputsList inputs and outputs in a buffer.
C-c M-wsage-shell:copy-previous-output-to-kill-ringCopy the previous output to kill-ring

For more commands and key-bindings see the help using M-x describe-mode sage-shell-mode.

Editing a Sage File

When you visit a file with the suffix .sage, then sage-shell:sage-mode will be the major-mode of the buffer automatically.

To switch to sage-shell:sage-mode on a .py file, run M-x sage-shell:sage-mode. To use sage-shell:sage-mode every time you visit that file, you can add the following magic comment at the first line of the file:

# -*- mode: sage-shell:sage -*-

If you’ve activated Aliases you can instead use the following magic comment:

# -*- mode: sage -*-

The major mode sage-shell:sage-mode is almost the same as python-mode. The following new key-bindings are added:

KeyCommandDescription
C-c C-csage-shell-edit:send-bufferEvaluate the contents of the current buffer in the Sage process.
C-c C-rsage-shell-edit:send-regionEvaluate the currently marked region in the Sage process.
C-c C-jsage-shell-edit:send-line*Evaluate the current line in the Sage process.
C-c C-lsage-shell-edit:load-fileLoad the current file in the Sage process.
C-c C-zsage-shell-edit:pop-to-process-bufferSelect the Sage process buffer.

If you run multiple Sage processes, use M-x sage-shell:set-process-buffer to change which one will be used for the above functions.

Input History

To save the history of input evaluated in a Sage process and use in future Sage process (using the M-p keybinding), add the following to your Emacs init file:

(setq sage-shell:input-history-cache-file "~/.emacs.d/.sage_shell_input_history")

The file name in the above line is the path for storing the inputs and you can change it to what you prefer.

Emulating Worksheets: code blocks

Worksheets is a popular paradigm for structuring experiments in computer algebra systems, seen in Jupyter, the Sage Notebook, Maple and many other softwares. sage-shell-mode supports a lightweight type of this workflow using “code blocks”.

Essentially, you structure your source file in logical blocks of code, representing both your library code and your experiments. For instance:

### Implement the new algorithm
def my_helper(a):
    return a*2

def my_new_algorithm(x, y):
    return my_helper(x) + my_helper(y)


### Check the new algorithm on small input
print my_new_algorithm(1, 2)

### Check the new algorithm on big input
print my_new_algorithm(100, 300)

### Check that my algorithm is commutative using random input
def my_random_number():
    return randint(100, 200)

a, b = my_random_number(), my_random_number()
assert my_new_algorithm(a, b) == my_new_algorithm(b, a)

The blocks of code are logically delimited by lines starting with ###. In this case load(experiment.sage) is not a good alternative to the way one works with the Jupyter Notebook: rather, you want to evaluate the code block by block. You also want to be able to modifying an earlier or later block, run that, and then return to the block in the middle, etc.

sage-shell-mode comes with a small set of functions for accommodating this. In sage-shell:sage-mode, the following functions are provided:

KeyCommandDescription
C-M-{sage-shell-blocks:backwardMove backward one block, i.e. to previous ### delimiter.
C-M-}sage-shell-blocks:forwardMove forward one block, i.e. to next ### delimiter.
C-<return>sage-shell-blocks:send-currentSend the block that the point is currently in to the Sage process

In the Sage process buffer, the following functions are provided:

KeyCommandDescription
C-<return>sage-shell-blocks:pull-nextTake the block from the last visited sage-shell:sage-mode buffer and send to the Sage process.

As an example, if the point is in the body of my_new_algorithm, then C-<return> (or M-x sage-shell-blocks:send-current) would send the definitions of my_helper and my_new_algorithm to the Sage shell. Furthermore, it would print the “title” of the block:

sage: load('/tmp/sage_shell_mode3946wC1/sage_shell_mode_temp.sage')
--- Implement the new algorithm ---
sage:

The delimiter ### can be changed by setq the variable sage-shell-blocs:delimiter.

Inline display of LaTeX outputs and plots (a port of sage-view)

This feature is a port of sage-view. This requires dvipng and preview.sty.

To enable inline display of LaTeX outputs and plots in sage-shell-mode buffer, add the following code to your Emacs init file:

;; If you want to enable inline display of LaTeX outputs only,
;; uncomment the following line.
;; (setq sage-shell-view-default-commands 'output)

;; If you want to enable inline display of plots only,
;; uncomment the following line.
;; (setq sage-shell-view-default-commands 'plot)

(add-hook 'sage-shell-after-prompt-hook #'sage-shell-view-mode)

You can use the following commands to enable/disable inline display of LaTeX outputs and plots.

CommandDescription
sage-shell-view-toggle-inline-outputToggle inline display of LaTeX outputs while SageMath process is running.
sage-shell-view-toggle-inline-plotsToggle inline display of plots while SageMath process is running.

The following table shows some of customizable variables for sage-shell-view-mode. For further customization, run M-x customize-group RET sage-shell-view RET.

Customizable variableDescriptionDefault value
sage-shell-view-default-commandsIf equal to the symbol plots then will start inline plotting. If equal to the symbol output then will start typesetting output. Otherwise, if non-nil will start both.t
sage-shell-view-default-resolutionResolution used when converting from PDF to PNG. This value is passed to the -r option of the ghostscript command.125
sage-shell-view-latex-foreground-colorForeground color used in LaTeX image as string (e.g. “black”, “white”, “#de935f”) or nil. If it is nil, then the default foreground color will be used.nil
sage-shell-view-latex-background-colorSimilar to sage-shell-view-latex-foreground-color for background color.nil

SageTeX

sage-shell-mode can be conveniently used when writing Sage-powered LaTeX files using SageTeX.

TEXINPUTS

When a Sage process is spawned by sage-shell:run-sage or sage-shell:run-new-sage, then sage-shell-mode adds $SAGE_ROOT/local/share/texmf/tex/generic/sagetex/ to the environment variable TEXINPUTS in Emacs. If you do not want to change the environment variable, set sage-shell-sagetex:add-to-texinputs-p to nil.

Commands for SageTeX

Here is a list of commands for SageTeX. These commands load a .sagetex.sage file generated by SageTeX to the existing Sage process.

CommandRun latex before loadingRun latex after loading
sage-shell-sagetex:load-fileNoNo
sage-shell-sagetex:run-latex-and-load-fileYesNo
sage-shell-sagetex:compile-fileYesYes

There are similar commands to above, sage-shell-sagetex:load-current-file, sage-shell-sagetex:run-latex-and-load-current-file and sage-shell-sagetex:compile-current-file.

Here is a sample setting for AUCTeX users.

(eval-after-load "latex"
  '(mapc (lambda (key-cmd) (define-key LaTeX-mode-map (car key-cmd) (cdr key-cmd)))
         `((,(kbd "C-c s c") . sage-shell-sagetex:compile-current-file)
           (,(kbd "C-c s C") . sage-shell-sagetex:compile-file)
           (,(kbd "C-c s r") . sage-shell-sagetex:run-latex-and-load-current-file)
           (,(kbd "C-c s R") . sage-shell-sagetex:run-latex-and-load-file)
           (,(kbd "C-c s l") . sage-shell-sagetex:load-current-file)
           (,(kbd "C-c s L") . sage-shell-sagetex:load-file)
           (,(kbd "C-c C-z") . sage-shell-edit:pop-to-process-buffer))))

For example, you can run sage-shell-sagetex:compile-current-file by C-c s c in a LaTeX-mode buffer with this setting.

Customize the latex Command

You can change a latex command used by sage-shell-sagetex:compile-file and sage-shell-sagetex:compile-current-file by setting sage-shell-sagetex:latex-command or sage-shell-sagetex:auctex-command-name.

If you are an AUCTeX user, then customize sage-shell-sagetex:auctex-command-name to change the latex command. The value of sage-shell-sagetex:auctex-command-name should be a name of a command in TeX-command-list (i.e car of an element of the list TeX-command-list), e.g.:

(setq sage-shell-sagetex:auctex-command-name "LaTeX")

You can also use the variable sage-shell-sagetex:latex-command to change the latex command. For example, if you want to run latexmk after loading a .sagetex.sage file, then use the following setting:

(setq sage-shell-sagetex:latex-command "latexmk")

The default value of sage-shell-sagetex:latex-command is latex -interaction=nonstopmode. If sage-shell-sagetex:auctex-command-name is non-nil, then the value of sage-shell-sagetex:latex-command is ignored.

Customization

To customize sage-shell-mode, M-x customize-group RET sage-shell, M-x customize-group RET sage-shell-sagetex or M-x customize-group RET sage-shell-view.

Extensions

Screenshots

Automatic indentation and syntax highlighting work.

./images/indent.png

Completion with auto-complete-sage.

./images/ac.png

Completion with helm-sage.

./images/helm.png

./images/helm1.png

Workaround for Flycheck

To use flycheck-mode in a sage-shell:sage-mode buffer and a python-mode buffer, try the following code.

(dolist (ckr '(python-pylint python-flake8))
  (flycheck-add-mode ckr 'sage-shell:sage-mode))

(defun sage-shell:flycheck-turn-on ()
  "Enable flycheck-mode only in a file ended with py."
  (when (let ((bfn (buffer-file-name)))
          (and bfn (string-match (rx ".py" eol) bfn)))
    (flycheck-mode 1)))

(add-hook 'python-mode-hook 'sage-shell:flycheck-turn-on)

License

Licensed under the GPL.