A desktop user's guide to Nano, a command-line text editor

Previous Topic Next Topic
 
Posted by Radishrain Radishrain
Options
See also
https://www.growspice.com/Termux-tricks-td3491.html

So, now that I have an Android device and a bluetooth keyboard for it, I've decided to use Termux (downloaded from the F-Droid appstore). I've been wanting to program, write and stuff on a command-line app for Termux; so, after reviewing my options, I decided Nano was the best place to start. I've already used Nano before for small tasks, but I mostly just used my own GUI-based text editor that I programmed for Linux until now.

Before I tell you more about Nano, let me tell you about the alternatives I've discovered:

• pico
• wordgrinder (This is an actual command-line word processor. It's kind of cool, and similar to nano, although it requires heavy use of the menus for what I would want to do with it.)
• joe (I think this is another word processor,  but I didn't look at it too much.)
• jed
• jove
• Emacs
• Vim

There are a few others. Most really serious command-line gurus like either Emacs or Vim; they have a much bigger learning curve than Nano. Nano is the most similar thing I've found for the command-line to a modern standard GUI-based text editor (and it has some cool features most of those don't).

Anyway, here's a comparison of the shortcuts for doing stuff in a standard GUI-based text editor and Nano:

Standard GUI-based text editor:
• Copy: ctrl+c
• Cut: ctrl+x
• Paste: ctrl+v
• Select all: ctrl+a
• Go to the beginning of the current line: home
• Go to the end of the current line: end
• Go to the beginning of the document: Ctrl+home key
• Go to the end of the document: Ctrl+end key
• Go left one word: Ctrl+left arrow key
• Go right one word: Ctrl+right arrow key
• Go up one paragraph: Ctrl+up arrow key
• Go down one paragraph: Ctrl+down arrow key
• Select from the current position to the beginning of the current line: shift+home
• Select from the current position to the end of the current line: shift+end
• Select from the current position to the beginning of the document: Ctrl+shift+home key
• Select from the current position to the end of the document: Ctrl+shift+end key
• Select to the left one word: Ctrl+shift+left arrow key
• Select to the right one word: Ctrl+shift+right arrow key
• Select up one paragraph: Ctrl+shift+up arrow key
• Select down one paragraph: Ctrl+shift+down arrow key
• Delete previous word: ctrl+backspace
• Delete next word: ctrl+delete
• Find: Ctrl+f
• Find next: Ctrl+g
• Find previous: Ctrl+shift+g
• Replace: Ctrl+h
• Undo: Ctrl+z
• Redo: Ctrl+shift+z
• New tab (new blank unsaved file in another tab): Ctrl+t
• New window: Ctrl+n
• Close tab: Ctrl+w
• Next tab: Ctrl+tab
• Previous tab: Ctrl+shift+tab
• Open file: Ctrl+o
• Save: Ctrl+s
• Save as: Ctrl+shift+s
• PageUp: PgUp
• PageDown: PgDn
• Toggle wordwrap: alt+y
• Jump to line number: ctrl+j

Now here's how you do things in Nano:
• Copy: alt+6
• Cut: ctrl+k
• Paste: ctrl+u (If you're running nano in Termux, Ctrl+Alt+v will paste from the Android clipboard instead of nano's.)
• Select all: no shortcut for this; try Ctrl+end then Ctrl+shift+home then Ctrl+k; you can make a macro to function like select all, though: to do this, try pressing shift+alt+: then ctrl+end then ctrl+shift+home then shift+alt+: (then you can just press alt+; to select all--but you can't have more than one macro to work with at the same time; so, if you make another macro, selecting all with alt+; won't work anymore)
• Go to the beginning of the current line: home
• Go to the end of the current line: end
• Go to the beginning of the document: Ctrl+home key
• Go to the end of the document: Ctrl+end key
• Go left one word: Ctrl+left arrow key
• Go right one word: Ctrl+right arrow key
• Go up one paragraph: Ctrl+up arrow key
• Go down one paragraph: Ctrl+down arrow key
• Select from the current position to the beginning of the current line: shift+home
• Select from the current position to the end of the current line: shift+end
• Select from the current position to the beginning of the document: Ctrl+shift+home key
• Select from the current position to the end of the document: Ctrl+shift+end key
• Select to the left one word: Ctrl+shift+left arrow key
• Select to the right one word: Ctrl+shift+right arrow key
• Select up one paragraph: Ctrl+shift+up arrow key
• Select down one paragraph: Ctrl+shift+down arrow key
• Delete previous word: alt+backspace (or if you have the settings in nanorc below, Ctrl+backspace and Ctrl+h will do it)
• Delete next word: ctrl+delete
• Find: Ctrl+w
• Find backwards: Ctrl+q
• Find next: alt+w; or ctrl+w then enter
• Find previous: alt+q
• Replace: Ctrl+\
• Undo: alt+u
• Redo: alt+e
• New buffer (basically the same thing as a new tab, without a tab bar): Ctrl+t then alt+f; then press enter
• Close current buffer: Ctrl+x
• Next buffer: alt+right
• Previous buffer: alt+left
• Open multiple files, each in a buffer (at nano startup): open them with nano (e.g. nano test.txt test2.txt, or to open all txt files in a folder, nano *.txt)
• Open file (when nano is already open): ctrl+r
• Open a file in a new buffer (when nano is already open): ctrl+r; alt+f (or Esc; f); type the name of the file; press enter.
• Save: Ctrl+s
• Save as: Ctrl+o (warning: if you have something selected, it'll only save what's selected, however)
• PageUp: PgDn
• PageDown: PgUp
• Toggle wordwrap: alt+s
• Jump to line number: ctrl+shift+- (ctrl+_)
• Spellcheck: F12 (You actually need to have a spellchecker installed, and enable it with .nanorc or such.)
• Alt+c: Toggle the statusbar on and off. (If you want line numbers instead, do `set linenumbers` in the nanorc file below. I have them off since they're kind of bright.)

You may want to create the file ~/.nanorc with the following contents, to make some features closer to the modern GUI-based text editor standard:
set tabsize 4
set tabstospaces
set nowrap
set softwrap
set autoindent
set atblanks
set afterends
set zap
#set nonewlines
#set multibuffer
set speller "hunspell -x -c"
set rawsequences
bind ^H chopwordleft main
bind F1 scrollup main
bind F2 scrolldown main

Those bindings to F1 and F2 (you can change them to other F-keys, or del and ins) are to make it so you can scroll more like an e-reader (without having to scroll all the way up and down before the screen moves). You may need to disable F-keys in your terminal settings first.

Also, add this to ~/.bashrc:
echo -ne "\e[3 q" #Blinking underlined
#echo -ne "\e[4 q" #Underlined

If you keep the default block cursor it'll make it seem like you're selecting one more character than you are when you're selecting to the right.

Updating nano:
To get the latest version of nano's source code (because distributions sometimes have old versions of nano), I recommend compiling it manually (I did this on Xubuntu 18.04.5 LTS) if that's the only way to get the latest version.
• To get dependencies, if you're on Ubuntu, type `sudo apt-get build-dep nano` (and maybe uninstall the one that's already there; I did).
• Download the latest version from here: https://www.nano-editor.org/download.php (I did this with version 5.8.)
• Decompress the file
• `./configure`
• `make`
• `sudo make install`
• If you don't restart your command-line, type `bash` to get it to show up in your path.

Some issues with Nano:
• Nano doesn't delete selected text when you type, although delete and backspace will delete selected text if `set zap` above is there. If you want to delete a portion of selected text when `set zap` above isn't enabled, press ctrl+k (which will cut it, and thus delete it; but this will also put it in your clipboard). You can also press alt+delete to delete selected text without putting it on the clipboard, but be careful as it does something else if there's no selected text.
• Note that `set rawsequences` disables mouse support (if you have it enabled, which I don't above). However, it needs to be set if you want ctrl+backspace to delete the word to the left; alternatively, you can make a script that executes nano with --raw for those times when you don't care to use a mouse (don't forget to make it executable with chmod +x):

#!/bin/bash

nano --raw "$@"

Notes:
• Nano has multiple shortcuts for a lot of things (so if you don't like the ones I mentioned above, there may be others).
• This post is about GNU nano, version 5.5 on Termux, compiled options: --disable-libmagic --disable-nls --enable-utf8

Some sources:
https://www.nano-editor.org/dist/latest/nanorc.5.html
https://forums.bunsenlabs.org/viewtopic.php?id=1731
https://gist.github.com/Herteby/148b858a367baf96d38f776234af500a

2 Comments

classic Classic list List threaded Threaded
Radishrain Radishrain
Reply | Threaded
Open this post in threaded view
|

Re: A desktop user's guide to Nano, a command-line text editor

This post was updated on .
If you want to know how to do custom operations on selected text in nano, this post is for you:

First of all, make a python script, make it executable, and put it in your path (so it can be called anywhere). If you wish to modify selected text, rather than just print something in nano, you'll need to make the program so you can pipe it in. Call the command like this: ctrl+t; then type `|myCommand myArg1 myArg2` (not counting the backtics, of course). Note that Python scripts don't have to end in `.py` to run.

Python-style regular expression search/replace:

To do regular expression searches with nano, you could try the built-in features, but they won't find or replace new lines.

I prefer Python regular expressions. So, I'm going to tell you how to use those in nano.

Here's the code:

reg.py:
#!/usr/bin/env python3

import re, sys;

text=sys.stdin.read();
reg="";
if len(sys.argv)==3:
    #Usage: ctrl+t; |reg.py "my regex" "my replacement" (don't forget the quotes, or some such); this is the default usage for two arguments.
    reg=sys.argv[1];
    rep=sys.argv[2];
    result=re.sub(reg, rep, text);
elif len(sys.argv)==2: #Usage: ctrl+t; |reg.py "my regex". Using one argument replaces the selected text with the text that matches the regular expression, delimited by new lines (press alt+u to undo this action on nano). The argument must be surrounded in quotes.
    reg=sys.argv[1];
    result="\n".join(re.findall(reg, text));
else:
    result=re.sub(r"", r"", text); #If you have no arguments, you'll need to edit the regular expression here to use it as the default.
print(result);

For doing ascending/descending/shuffle sorts, here is some code for more files (do `pip install natsort` first, if you don't have natsort installed):

This file is needed for the other ones to work:
import natsort, traceback, math, re, random;

"""
See these files to pipe into nano:
asc.py
uasc.py
desc.py
udesc.py
shu.py
ush.py
"""

def sort_chunks(myList):
    #This takes a sorted list, and sorts each chunk of entries that would be the same if they had the same casing (according to the GROUPLETTERS algorithm). The returned list amounts to what GROUPLETTERS|IGNORECASE ought to result in, IMO.
    finds=[];
    previous_x=None;
    for x in myList:
        if len(finds)==0:
            finds.append([x]);
        else:
            if previous_x.lower()==x.lower():
                finds[-1].append(x);
            else:
                finds.append([x]);
        previous_x=x;
    newList=[];
    for x in finds:
        case_sorted=natsort.natsorted(x, alg=natsort.ns.GROUPLETTERS);
        for y in case_sorted:
            newList.append(y);
    return newList;

def sorted_nums(myList, rev=False, cs=False):
    #The name is a misnomer and needs to be changed now that natsort sorts the numbers.
    result=None;
    if cs==True:
        result=natsort.natsorted(myList, alg=natsort.ns.GROUPLETTERS);
    else:
        result=natsort.natsorted(myList, alg=natsort.ns.IGNORECASE);
        try:
            result=sort_chunks(result);
        except:
            traceback.print_exc();
    if rev==True:
        result.reverse();
    return result;

def group_item_split(text):
    split_text=text.split("\n");
    minimal_indent=math.inf;
    for x in split_text:
        found=re.findall(r"^ *", x);
        for y in found:
            if len(y)<minimal_indent:
                minimal_indent=len(y);
    spaces="";
    for x in range(0,minimal_indent):
        spaces+=" ";
    new_list=[];
    i=0;
    new_i=0;
    while i<len(split_text.copy()):
        modified=False;
        if i==0:
            split_text[i]=spaces+split_text[i].lstrip();
        if split_text[i].startswith(spaces+" "):
            new_list[new_i-1]=new_list[new_i-1]+"\n"+split_text[i];
            modified=True;
        else:
            new_list.append(split_text[i]);
        if modified==False:
            new_i+=1;
        i+=1;
    return new_list;


def usplit(text, splitArgs, unique=True, gr=False):
    #Unique split
    #Allows removing duplicates from a split list.
    #if gr is True it will group indented material with its parent line, for when you are sorting lines (instead of sorting each line no matter the indents); this treats splitArgs as if it were "\n"
    tList=None;
    if gr==False:
        if unique==True:
            tList=list(set(text.split(splitArgs)));
        else:
            tList=text.split(splitArgs);
    else:
        if unique==True:
            tList=list(set(group_item_split(text)));
        else:
            tList=group_item_split(text);
    return tList;

def sort_ascending(text, rev=False, gr=True, unique=True):
    if text!="":
        if "\n" in text:
            tList=usplit(text, "\n", unique, gr=gr);
            tList=sorted_nums(tList, rev);
            text="\n".join(tList);
        elif gr==True and (", " in text or "," in text):
            text=re.sub(r", *", r",", text);
            tList=usplit(text, ",", unique);
            tList=sorted_nums(tList, rev);
            text=", ".join(tList);
        elif " " in text:
            text=re.sub(r" +", r" ", text);
            tList=usplit(text, " ", unique);
            tList=sorted_nums(tList, rev);
            text=" ".join(tList);
        else:
            tList=None;
            if unique==True:
                tList=list(set(list(text)));
            else:
                tList=list(text);
            tList.sort(reverse=rev);
            text="".join(tList);
    return text;
            
def sort_descending(text, gr=True, unique=True):
    return sort_ascending(text=text, rev=True, gr=gr, unique=unique);

def shuffle(text, gr=True, unique=True):
    if text!="":
        if "\n" in text:
            tList=usplit(text, "\n", unique, gr=gr);
            random.shuffle(tList);
            text="\n".join(tList);
        elif gr==True and (", " in text or "," in text):
            text=re.sub(r", *", r",", text);
            tList=usplit(text, ",", unique);
            random.shuffle(tList);
            text=", ".join(tList);
        elif " " in text:
            text=re.sub(r" +", r" ", text);
            tList=usplit(text, " ", unique);
            random.shuffle(tList);
            text=" ".join(tList);
        else:
            tList=None;
            if unique==True:
                tList=list(set(list(text)));
            else:
                tList=list(text);
            random.shuffle(tList);
            text="".join(tList);
    return text;


asc.py: (sort ascending; duplicates are not removed)
#!/usr/bin/env python3

#Pipe this into nano to sort selected text in ascending order: ctrl+t; |asc.py

import sortshuffle, sys;

text=sys.stdin.read();

result=sortshuffle.sort_ascending(text, gr=False, unique=False);

print(result);

uasc.py: (sort ascending; duplicates are removed)
#!/usr/bin/env python3

#Pipe this into nano to sort selected text in ascending order: ctrl+t; |uasc.py

import sortshuffle, sys;

text=sys.stdin.read();

result=sortshuffle.sort_ascending(text, gr=False, unique=True);

print(result);

desc.py (sort descending; duplicates are not removed)
#!/usr/bin/env python3

#Pipe this into nano to sort selected text in ascending order: ctrl+t; |desc.py

import sortshuffle, sys;

text=sys.stdin.read();

result=sortshuffle.sort_descending(text, gr=False, unique=False);

print(result);

udesc.py (sort descending; duplicates are removed)
#!/usr/bin/env python3

#Pipe this into nano to sort selected text in ascending order: ctrl+t; |udesc.py

import sortshuffle, sys;

text=sys.stdin.read();

result=sortshuffle.sort_descending(text, gr=False, unique=True);

print(result);

shu.py: (shuffle; duplicates are not removed)
#!/usr/bin/env python3

#Pipe this into nano to sort selected text in ascending order: ctrl+t; |shu.py

import sortshuffle, sys;

text=sys.stdin.read();

result=sortshuffle.shuffle(text, gr=False, unique=False);

print(result);

ush.py (shuffle; duplicates are removed)
#!/usr/bin/env python3

#Pipe this into nano to sort selected text in ascending order: ctrl+t; |ush.py

import sortshuffle, sys;

text=sys.stdin.read();

result=sortshuffle.shuffle(text, gr=False, unique=True);

print(result);

The sort and shuffle functions work differently depending on what you're sorting or shuffling (for instance, if it's a word, it'll sort the characters of the word; if it's multiple words on a line, it'll sort the words; if it's multiple lines, it'll sort the lines; natsort allows numbers to be sorted numerically, rather than alphabetically. If you want indented material to be grouped with the outermost parent line, do `gr=True` in the calling function.
Climate: BSk
USDA hardiness zone: 6
Radishrain Radishrain
Reply | Threaded
Open this post in threaded view
|

Re: A desktop user's guide to Nano, a command-line text editor

This post was updated on .
In reply to this post by Radishrain
To get an immersive experience where you just have words you type and nothing else, do this:

nano -0

or

nano --zero

Pressing alt+x will toggle the stuff at the bottom on and off. I'm not sure how to toggle the stuff at the top on and off without restarting, though.

I make a script to run nano with this:

#!/bin/bash

nano -0 "$@"
Climate: BSk
USDA hardiness zone: 6
Feedback, Links, Privacy, Rules, Support, About