Modify or hook into Jupyter's tab completion - jupyter-notebook

I was wondering if there was a way to modify Jupyter Lab or Notebook's tab-complete functionality. For example, if I type "\alpha", and then press the tab key, I will get the UTF-8 character "α" in the cell.
Is there any way that I can do a custom "[string without spaces]" to tab-complete into some specific UTF-8 character or string?
e.g. "\implies" + tab -> "⇒"
I can see a large number of use cases for this in my programming life, so I was wondering if Jupyter (Lab or Notebook) offered the ability to modify some settings (or load in a file) that maps strings to a tabbed output. Or is there a different idea that you could use to implement this?
Thanks!

Jupyter is (based on) IPython and it's completion engine - we can make use of it.
Update: you can override latex_symbols dict to get the behavior you want:
from IPython.core.latex_symbols import latex_symbols
latex_symbols['\\implies'] = '⇒'
You should be able to build upon this example to make it work with a whole range of characters.
Initial answer/another solution: you can hook into IPython completers, though it would not work exactly as you wish: it won't replace the text, but just append a special character. Here is an example:
from IPython import get_ipython
def implies_competer(ipython, event):
return ['⇒']
ipython = get_ipython()
ipython.set_hook('complete_command', implies_competer, re_key='.*implies')
Then when you type (the space after the keyword is important):
and then press tab, you will get:

Related

How to search previously executed commands in the Julia REPL?

Is there a quick way to search old commands which were run in the Julia REPL? Using the up arrow to go back in time seems to have a limit on its history and it is also quite cumbersome.
One of the five REPL models available in Julia is the "Search mode" which allows you to search through previously executed commands from the REPL. You can click "Control" + "r" to open search mode like is shown below:
(reverse-i-search)`':
There is also a forward search available with "Control" + "s". You can read more about Julia's REPL Search mode here: https://docs.julialang.org/en/v1/stdlib/REPL/#Search-modes
In addition to "real" search, you can also enter the beginning of a previous line and scroll up in the history (using ↑ or Ctrl-P) to switch between all previously entered lines starting with the same prefix.
So, if you had previously entered x = some_complicated_expression, you can write x = and go up until the line you were looking for appears.
Checkout: https://kristofferc.github.io/OhMyREPL.jl/latest/features/fzf/#Fuzzy-REPL-history-search
Which will be easier to use than reverse-i-search

Atom - Force Tab Width 2

I just switched from Sublime Text to Atom in order to turn completely open source.
I have trouble with something very very simple: I want Atom to use always (!) and under any circumstances tab width 2 and replace tab with spaces. This setting is so simple in gedit or Sublime Text, but no matter what I am trying: When I start a new file, tab size is 2 (good!). When I use an existing file, tab size is sometimes 4. I find that a bit annoying.
My current setting in Editor are seen in the screenshot:
There is more than one tab setting
Each package (such as python-language) has its own tab setting(s). Whether the language uses the global default or its own default is up to whoever created the package, but you can generally override it.
In your screenshot, you have set the "Tab Type" to "soft". That will take care of using spaces rather than tabs. You have left the default tab width of 2. That is your global setting.
Now, if you look under "Packages" and search for "python" you will find a package named "language-python". Click on its settings button and you will find a number of syntax-specific settings.
Python Grammar
Python Console Grammar
Python Traceback Grammar
Regular Expressions (Python) Grammar
Each of those grammars has its own Tab Length setting. You can set them explicitly to 2 here to override the package's default. (You probably mostly care about the first one, Python Grammar.)
Python is different
In the case of Python, the package is explicitly configured to default to 4 spaces, probably because Python is very opinionated about whitespace, and PEP 8 recommends 4-space indents. You can see the default package setting here in the package's source:
https://github.com/atom/language-python/blob/master/settings/language-python.cson
'autoIndentOnPaste': false
'softTabs': true
'tabLength': 4
This overrides the global default. That's why Python Grammar does not honor the global tab width, the way that most packages do.
Sometimes there are package overrides
Additionally, certain packages will override your settings for syntax reasons. For example, language-make will override and use real tabs instead of spaces, because that is required by make.
In the case of Python, there is an override to use spaces. The language-python settings page offers a spot for you to change the indentation level, but it does not offer a way to switch to using tab characters. (That's probably justifiable, as tab characters and mixed indentation in Python are a very common cause of difficult-to-debug syntax errors.)
You might need to reload
Lastly, sometimes settings don't take effect completely until you reload the Atom window. You can use the Window: Reload command to do so. Or using the keyboard:
Mac: CtrlOptCmdL
Windows/Linux: CtrlAltR
This is what worked for me.
Disable all non-default packages
Open ~/.atom/config.cson, and append this (same level than the "*" element)
:
".python.source":
editor:
autoIndent: true
tabLength: 2
Re-enable all packages.
I got this help from someone else. Not my own discovery. However, for confidentiality, I cannot cite the source.
Based on soham's answer, I found that setting all tabLength: fields in ~/.atom/config.cson (assuming osx) to your desired length solved the problem.

IPython notebook: define a dummy cell magic that simply runs the cell as usual

How can I define a simple cell magic that just executes the cell as if the %%mymagic wasn't there?
The context is that we are using the wonderful IPython parallel framework. In some places, we also use its defined %%px magic. But sometimes we'd like to run the same notebook without a cluster (local only). In that case, %%px isn't defined and I would have to comment it out. Instead, in that case I'd like to redefine %%px so that:
%%px: would be a no-op.
%%px --local: just runs the cell, no other side-effect.
Alternatively, all %%px (with --local or not) could just run the cell, if that's simpler.
Another approach would be to create an ipyparallel Client that is a fake one, i.e. with 0 nodes (but would still operate correctly, e.g. with regard to %%px --local). But that would be for another question.
Things I've tried:
%alias_magic px time (after all, I don't care if the cell is timed). Unfortunately, %%time doesn't take arguments and chokes on --local.
Define my own "no-op" magic:
if USE_CLIENT:
pass
else:
# temporarily define %%px cell magic
from IPython import get_ipython
def px(line, cell):
"""Do nothing"""
pass
get_ipython().register_magic_function(px, 'cell')
but that succeeds a little too well at doing really nothing (i.e. the cells are not executed).
Look into IPython/core/magics/execution.py to see if there is any hook I could reuse (something that would just execute the cell). I haven't found, but perhaps I haven't looked hard enough.
Any other idea?
I think the relevant command is
self.shell.run_cell(cell)
We can define a magic command that just does not have effect as:
def f(line, cell):
print('==> line:[{}]'.format(line))
print('==> cell:\n # {}'.format('\n # '.join(cell.split())))
print('==================================================================')
res = get_ipython().run_cell(cell)
get_ipython().register_magic_function(f, 'cell', 'cache')
Here is an example run:
In your case, try:
if USE_CLIENT:
pass
else:
# temporarily define %%px cell magic
from IPython import get_ipython
def px(line, cell):
res = get_ipython().run_cell(cell)
get_ipython().register_magic_function(px,'cell','px')

OptionParser in ipython notebook?

I am enjoying developing inside the ipython notebook, but I am having a problem when I want to write a main() function that reads the command line args (with OptionParser, for example). I want to be able to export the code to a .py file and run it from the command line, but I haven't found a way to have a main() that runs both in the notebook with predefined arguments or from the command line with python and command line args. What is the secret?
In case that is not clear, I would like to do something like this:
if __name__ == '__main__':
# if in the notebook
vals = {'debug':True, 'tag_file': 't.tags'}
options = Object()
for k,v in vals.items():
options.setattr(k,v)
args = 'fname1.txt'
# if running as a command line python script
from optparse import OptionParser
parser = OptionParser()
parser.add_option('-d','--debug',action='store_true',dest='debug')
parser.add_option('-t','--tags',action='store',dest='tag_file')
options,args = parser.parse_args()
You cannot determine that you are in an IPython notebook or a qtconsole, or a simple IPython shell, for the simple reason the 3 can be connected to the same kernel at the same time.
It would be like asking, what color is the current key the user is typing. You could get it by looking the plugged usb devices and look for images on the internet and guess the keyboard color, but nothing guarantees you it will be accurate, nor that it won't change, and user can have multiple keyboard plugged, or even painted keyboard.
It is really the same with the notebook, Even if you determine you are in ZMQKernel, are you speeking to qtconsole or webserver ? Again, you found that you were talking to the webserver, are you talking to JS or Emacs ? And so on and so forth.
The only thing you can do, you can ask the user.
What is reliable, is test wether you are in IPython or not.
If you really but reeaaalllyy want a way, as until now, the notebook is the only thing that can display Javascript. And javascript can execute code in pyton. So you might be able to create something that display JS that send back info to the kernel. And using thread and timer you can say that you were not in a notebook (but you will have a race condition).
Don't worry about the distinction. Just set default values, and unless they are overridden from the command line, use those.
if __name__ == '__main__':
parser = OptionParser()
parser.add_option('-d', '--debug', action='store_true', dest='debug',
default=True)
parser.add_option('-t','--tags',action='store',dest='tag_file',
default='t.tags')
options, args = parser.parse_args()
if not args:
args = ['fname1.txt']

Evaluating buffer until the cursor

I am trying to create a key binding for "Evaluate buffer till here" in Emacs & ESS, which is situated in ESS => ESS Eval menu. Most of the commands in that menu are listed in help files (http://ess.r-project.org/Manual/ess.html, and in Emacs options), but this particular one is not. If I place following code in .emacs file:
(eval-after-load "ess-mode" '(define-key ess-mode-map (kbd "C-.") 'ess-eval-buffer-till-here))
I get a following message when trying to use the binding: Symbol´s function definition is void: ess-eval-buffer-till-here. Obviously I am calling for wrong name. What is the right name for this command and how can I see all of the commands for ESS?
So it's a menu item? Type C-hk and then select that item.
(Menus are implemented as keymaps, so this is just the normal describe-key functionality.)
You can also see the non-interactive call form of the last command with C-xESCESC or C-xM-:. It's easy to figure out the command name once you have that. (thanks event_jr)
For listing all commands, most modes will list all their key bindings in their docstring, so you can use C-hm to describe the modes in use in the buffer.
As there may be commands without bindings, you could also use M-x apropos-command to list them all (most likely specifying ^ess as a pattern, if it uses that as a consistent name space).

Resources