10

In German you start mails and letters with "Sehr geehrter Herr ....".

I am tired of typing this again and again. And I am tired of configuring applications to give me shortcuts to insert text blocks like this.

Is there a way to insert comment text blocks with the desktop environment?

This way I could insert text blocks in vi, thunderbird, firefox, libreoffice...

Another example: I often need to insert my ssh-pub-key somewhere. I know how to use ssh-copy-id, but again a desktop solution to give me access to a configurable list of text blocks would be great.

Zanna
  • 69,223
  • 56
  • 216
  • 327
guettli
  • 2,932
  • 12
  • 67
  • 115

2 Answers2

14

I use AutoKey it installs from the Ubuntu Software Center

real easy to use

I have added "phrase"s like my email address example@gmail.com by typing gm plus hitting tab <tab>

enter image description here

enter image description here

BOB
  • 651
  • 6
  • 7
  • 1
    Nice application. Works in the terminal and in gedit. The docs are written by experts ... too many details, no overview :-). But it works - thank you. – guettli Jul 17 '16 at 10:36
  • `sudo apt install autokey-gtk` if you're so inclined. And a [very nice tutorial](https://www.maketecheasier.com/autokey-make-your-own-keyboard-shortcuts-in-linux/) – brasofilo Feb 11 '22 at 01:42
10

The script below does the job with applications that use Ctrl+V to paste text. It is important to know that it will not work in the gnome-terminal* for example.
I tested it on a.o. Firefox, Thunderbird, Libreoffice, Sublime Text and Gedit without any problem.

How it works

When the script is called, a window appears, listing snippets you defined. Choose an item (or type its number) and the text fragment will be pasted in the frontmost window of any application that is Ctrl+V "-compatible":

enter image description here

Adding / editing snippets

When you choose manage snippets, the script's folder in ~/.config/snippet_paste opens up in nautilus. To create a new snippet, simply create a text file with your snippet's text. Don't mind the name you give the file; as long as it is plain text, it is ok. The script only uses the file's content and creates a numbered list of all the files ('content) it finds.

enter image description here

If the snippets directory (~/.config/snippet_paste) does not exist, the script creates it for you.

How to use

  • first install xdotool and xclip, if it is not installed on your system:

    sudo apt-get install xdotool
    

    and

    sudo apt-get install xclip
    
  • Copy the script below, save it as paste_snippets.py, run it by the command:

    python3 /path/to/paste_snippets.py
    

The script

#!/usr/bin/env python3

import os
import subprocess

home = os.environ["HOME"]
directory = home+"/.config/snippet_paste"
if not os.path.exists(directory):
    os.mkdir(directory)
# create file list with snippets
files = [
    directory+"/"+item for item in os.listdir(directory) \
         if not item.endswith("~") and not item.startswith(".")
    ]
# create string list
strings = []
for file in files:
    with open(file) as src:
        strings.append(src.read())
# create list to display in option menu
list_items = ["manage snippets"]+[
    (str(i+1)+". "+strings[i].replace("\n", " ").replace\
     ('"', "'")[:20]+"..") for i in range(len(strings))
    ]
# define (zenity) option menu
test= 'zenity --list '+'"'+('" "')\
      .join(list_items)+'"'\
      +' --column="text fragments" --title="Paste snippets"'
# process user input
try:
    choice = subprocess.check_output(["/bin/bash", "-c", test]).decode("utf-8")
    if "manage snippets" in choice:
        subprocess.call(["nautilus", directory])
    else:
        i = int(choice[:choice.find(".")])
        # copy the content of corresponding snippet
        copy = "xclip -in -selection c "+"'"+files[i-1]+"'"
        subprocess.call(["/bin/bash", "-c", copy])
        # paste into open frontmost file
        paste = "xdotool key Control_L+v"
        subprocess.Popen(["/bin/bash", "-c", paste])
except Exception:
    pass

If you are not using nautilus

If you are using another file browser, replace the line (29):

subprocess.Popen(["nautilus", directory])

by:

subprocess.Popen(["<your_filebrowser>", directory])

Putting the script under a shortcut key combination

For more convenient use, you can create a shortcut to call the script:

  • System Settings → KeyboardShortcutsCustom Shortcuts

  • Click + to add your command:

    python3 /path/to/paste_snippets.py
    

The script is also posted on gist.gisthub.


*EDIT

The version below automatically checks if the (gnome-) terminal is the frontmost application, and changes the paste command automatically into Ctrl+Shift+V instead of Ctrl+V

Usage and set up is pretty much the same.

The script

#!/usr/bin/env python3

import os
import subprocess

home = os.environ["HOME"]
directory = home+"/.config/snippet_paste"
if not os.path.exists(directory):
    os.mkdir(directory)
# create file list with snippets
files = [
    directory+"/"+item for item in os.listdir(directory) \
         if not item.endswith("~") and not item.startswith(".")
    ]
# create string list
strings = []
for file in files:
    with open(file) as src:
        strings.append(src.read())
# create list to display in option menu
list_items = ["manage snippets"]+[
    (str(i+1)+". "+strings[i].replace("\n", " ").replace\
     ('"', "'")[:20]+"..") for i in range(len(strings))
    ]
# define (zenity) option menu
test= 'zenity --list '+'"'+('" "')\
      .join(list_items)+'"'\
      +' --column="text fragments" --title="Paste snippets" --height 450 --width 150'

def check_terminal():
    # function to check if terminal is frontmost
    try:
        get = lambda cmd: subprocess.check_output(cmd).decode("utf-8").strip()
        get_terms = get(["xdotool", "search", "--class", "gnome-terminal"])
        term = [p for p in get(["xdotool", "search", "--class", "terminal"]).splitlines()]
        front = get(["xdotool", "getwindowfocus"])
        return True if front in term else False
    except:
        return False

# process user input
try:
    choice = subprocess.check_output(["/bin/bash", "-c", test]).decode("utf-8")
    if "manage snippets" in choice:
        subprocess.call(["nautilus", directory])
    else:
        i = int(choice[:choice.find(".")])
        # copy the content of corresponding snippet
        copy = "xclip -in -selection c "+"'"+files[i-1]+"'"
        subprocess.call(["/bin/bash", "-c", copy])
        # paste into open frontmost file
        paste = "xdotool key Control_L+v" if check_terminal() == False else "xdotool key Control_L+Shift_L+v"
        subprocess.Popen(["/bin/bash", "-c", paste])
except Exception:
    pass
BeastOfCaerbannog
  • 12,964
  • 10
  • 49
  • 77
Jacob Vlijm
  • 82,471
  • 12
  • 195
  • 299
  • Hi @guettli, could you give some feedback on the answer? does it work for you, did you run into problems etc? – Jacob Vlijm Nov 05 '14 at 07:39
  • Your solution should work, but I still not happy. I wrote down my requirements here https://github.com/guettli/ten-flying-fingers. Current best solution seems to be ibus-typing-booster with a custom word/text list. – guettli Jun 02 '15 at 07:26
  • 1
    @guettli If requirements are not in the question, you can't expect an answer to meet your requirements :\ I think it is pretty much what you literally asked for. (b.t.w. I am using it myself ever since) – Jacob Vlijm Jun 02 '15 at 07:31