26 Commits

Author SHA1 Message Date
53e4038065 Expand word delimiter characters 2017-02-05 12:31:09 -05:00
f93f6d7bd9 Disable bold fonts 2016-12-22 14:49:32 -05:00
0bfde9df6d Shut up about UTF-8 mouse mode (1005) from tmux 2016-12-22 14:48:32 -05:00
b1d4782674 Add my config.h
Adds customized font, selection word boundary character for tmux, and
decreases tab width to 4 spaces.
2016-12-22 14:48:32 -05:00
923cbdd9d1 Hide cursor when you start typing 2016-12-22 14:48:31 -05:00
a2940a5559 clipboard: Also copy to 'Ctrl-V' in addition to 'middleclick' clipboard 2016-12-22 14:48:31 -05:00
552d828ce0 solarized: Modify dark colors to Aaron's liking 2016-12-22 14:48:31 -05:00
b03129f569 solarized: Apply solarized-dark color theme 2016-12-22 14:48:31 -05:00
e3d2f4b5cc solarized: Disable lighting up bold colors
This is the equivalent of:
	URxvt.intensityStyles: false
2016-12-22 14:48:31 -05:00
c63a87cd93 Move column and row default numbers into config.h 2016-12-16 10:50:23 +01:00
e44832408b Revert "Initial font size issue."
This reverts commit 424202798b.
2016-11-24 20:21:19 +01:00
fa9a459972 Fixed 'missing glyph doesn't use fontconfig config substitutions' bug
XftFontMatch does display-specific font configuration (commit 528241a).
Nice. Unfortunately, when we switched from FcFontMatch, we also stopped
storing the post-Fc{Config,Default}Substitute FcPattern for future
lookups. The result is that if a glyph isn't found in the primary font,
secondary font lookups use the original FcPattern, not the configured
one. If you have custom fontconfig rules (like me), this can be
disappointing.

I basically just copied the guts out of XftFontMatch[1] and saved
the intermediate configured FcPattern. Could be related to the bug that
inspired commit 4242027.

[1]: https://cgit.freedesktop.org/xorg/lib/libXft/tree/src/xftfont.c
2016-11-24 20:20:45 +01:00
740ada1447 make the various combinations of arrow keys and shift/control/meta work
When using st with screen, I've bound next, prev, new screen to
combinations like Ctrl-Alt-Right,Left,Down; xterm and (u)rxvt work fine
when this combination of modifiers is pressed, st does not seem to
transport all of them; a single modifier key is fine (e.g. Ctrl-Up,
Alt-Down etc., but combinations are not). While I'm not terribly
familiar with this, I have tried to hack config.h in a more or less
systematic way to generate the expected sequences.
2016-11-14 19:58:02 +01:00
424202798b Initial font size issue.
Hi,

When I specify a font by point size (I'm using "Inconsolata:size=12"),
characters that are substituted from another font because they are not in the
main one appear too small.  Doing a zoom reset fixes it.  For example:

Before: http://i.imgur.com/G4Mfv4X.png
After:  http://i.imgur.com/PMDhfQA.png

I found that adding the pixel size (acquired from the initial font load) to the
pattern then reloading the font fixes the problem.  I'm not sure if this is a
proper fix, though.
2016-11-14 19:27:55 +01:00
3ca7249c86 tic -s -> tic -sx (Treat unknown capabilities as user-defined.) 2016-11-14 19:05:47 +01:00
06f8cf8ca8 Add tmux capabilities to st.info 2016-11-14 19:05:11 +01:00
902a392b90 Make strdump(), csidump(), print to stderr
The two functions strdump(), csidump() are called to show errors and
their output is introduced by a message printed to stderr. Thus, it it
more consistent to have them print to stderr.

Moreover stderr is unbuffered (at least on Linux), making problems
immediately visible.
2016-11-14 18:36:38 +01:00
8c99915608 Do not use color when font attributes are supported
If fontconfig gives us a font without the attributes we asked for,
display an alternative color instead.
2016-10-23 17:56:46 +02:00
7854fde1ff st.1: add an entry for ISO-14755 shortcut 2016-10-22 10:43:18 +02:00
68bae9c7b1 Add support for iso14755
We launch dmenu for getting a codepoint, then convert it and send it to
the terminal.
2016-10-18 13:32:36 +02:00
331033f1f6 Add missing device path to '-l' example
Also, it's ttyS0 not ttySO.
2016-10-13 17:25:17 +02:00
f7398434b8 Add parsing of DCS q sequences
These sequences are used to operate with sixels, but they are still
str sequences, so they are finished with \a, ST or with a C1 control
code. This patch also disables utf8 handling for the case of sixels.
2016-09-14 08:27:32 +02:00
f0e2d28732 Add support for enabling/disabling utf
There are some ocasions where we want to disable the enconding/decoding of utf8, mainly
because it adds an important overhead. This is partial patch for ESC % G and ESC % @,
where they modified the way that st reads and write from/to the serial line, but it does
not modifies how it interacts with the X window part.
2016-09-13 14:01:18 +02:00
078337d745 Delete ncv capability from terminfo
We do not need to disable the previous ncv definition, because
there is not previous definition.
2016-09-09 13:11:06 +02:00
5ce853a1c1 st.info: do not prevent st from displaying attributes
With ncv set to 3, we prevent st from displaying A_STANDOUT and
A_UNDERLINE with colors while our virtual terminal is capable of it.
2016-09-09 11:05:11 +02:00
023225ef40 Update the LICENSE.
This is for the next release.
2016-08-11 16:30:29 +02:00
9 changed files with 762 additions and 123 deletions

2
FAQ
View File

@ -6,7 +6,7 @@ Use the excellent tool of [utmp](http://git.suckless.org/utmp/) for this task.
It means that st doesnt have any terminfo entry on your system. Chances are It means that st doesnt have any terminfo entry on your system. Chances are
you did not `make install`. If you just want to test it without installing it, you did not `make install`. If you just want to test it without installing it,
you can manualy run `tic -s st.info`. you can manualy run `tic -sx st.info`.
## Nothing works, and nothing is said about an unknown terminal! ## Nothing works, and nothing is said about an unknown terminal!

View File

@ -2,8 +2,8 @@ MIT/X Consortium License
© 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com> © 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>
© 2009 Anselm R Garbe <garbeam at gmail dot com> © 2009 Anselm R Garbe <garbeam at gmail dot com>
© 2012-2015 Roberto E. Vargas Caballero <k0ga at shike2 dot com> © 2012-2016 Roberto E. Vargas Caballero <k0ga at shike2 dot com>
© 2012-2015 Christoph Lohmann <20h at r-36 dot net> © 2012-2016 Christoph Lohmann <20h at r-36 dot net>
© 2013 Eon S. Jeon <esjeon at hyunmu dot am> © 2013 Eon S. Jeon <esjeon at hyunmu dot am>
© 2013 Alexander Sedov <alex0player at gmail dot com> © 2013 Alexander Sedov <alex0player at gmail dot com>
© 2013 Mark Edgar <medgar123 at gmail dot com> © 2013 Mark Edgar <medgar123 at gmail dot com>

View File

@ -49,7 +49,7 @@ install: all
@sed "s/VERSION/${VERSION}/g" < st.1 > ${DESTDIR}${MANPREFIX}/man1/st.1 @sed "s/VERSION/${VERSION}/g" < st.1 > ${DESTDIR}${MANPREFIX}/man1/st.1
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/st.1 @chmod 644 ${DESTDIR}${MANPREFIX}/man1/st.1
@echo Please see the README file regarding the terminfo entry of st. @echo Please see the README file regarding the terminfo entry of st.
@tic -s st.info @tic -sx st.info
uninstall: uninstall:
@echo removing executable file from ${DESTDIR}${PREFIX}/bin @echo removing executable file from ${DESTDIR}${PREFIX}/bin

2
README
View File

@ -24,7 +24,7 @@ Running st
If you did not install st with make clean install, you must compile If you did not install st with make clean install, you must compile
the st terminfo entry with the following command: the st terminfo entry with the following command:
tic -s st.info tic -sx st.info
See the man page for additional details. See the man page for additional details.

View File

@ -84,31 +84,23 @@ static unsigned int tabspaces = 8;
/* Terminal colors (16 first used in escape sequence) */ /* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = { static const char *colorname[] = {
/* 8 normal colors */ /* solarized dark */
"black", "#03171d", /* 0: black */
"red3", "#dc322f", /* 1: red */
"green3", "#859900", /* 2: green */
"yellow3", "#b58900", /* 3: yellow */
"blue2", "#268bd2", /* 4: blue */
"magenta3", "#d33682", /* 5: magenta */
"cyan3", "#2aa198", /* 6: cyan */
"gray90", "#eee8d5", /* 7: white */
"#001014", /* 8: brblack */
/* 8 bright colors */ "#cb4b16", /* 9: brred */
"gray50", "#586e75", /* 10: brgreen */
"red", "#657b83", /* 11: bryellow */
"green", "#839496", /* 12: brblue */
"yellow", "#6c71c4", /* 13: brmagenta*/
"#5c5cff", "#93a1a1", /* 14: brcyan */
"magenta", "#fdf6e3", /* 15: brwhite */
"cyan",
"white",
[255] = 0,
/* more colors can be added after 255 to use with DefaultXX */
"#cccccc",
"#555555",
}; };
@ -116,10 +108,10 @@ static const char *colorname[] = {
* Default colors (colorname index) * Default colors (colorname index)
* foreground, background, cursor, reverse cursor * foreground, background, cursor, reverse cursor
*/ */
static unsigned int defaultfg = 7; static unsigned int defaultfg = 12;
static unsigned int defaultbg = 0; static unsigned int defaultbg = 8;
static unsigned int defaultcs = 256; static unsigned int defaultcs = 14;
static unsigned int defaultrcs = 257; static unsigned int defaultrcs = 15;
/* /*
* Default shape of cursor * Default shape of cursor
@ -130,6 +122,13 @@ static unsigned int defaultrcs = 257;
*/ */
static unsigned int cursorshape = 2; static unsigned int cursorshape = 2;
/*
* Default columns and rows numbers
*/
static unsigned int cols = 80;
static unsigned int rows = 24;
/* /*
* Default colour and shape of the mouse cursor * Default colour and shape of the mouse cursor
*/ */
@ -138,12 +137,10 @@ static unsigned int mousefg = 7;
static unsigned int mousebg = 0; static unsigned int mousebg = 0;
/* /*
* Colors used, when the specific fg == defaultfg. So in reverse mode this * Color used to display font attributes when fontconfig selected a font which
* will reverse too. Another logic would only make the simple feature too * doesn't match the ones requested.
* complex.
*/ */
static unsigned int defaultitalic = 11; static unsigned int defaultattr = 11;
static unsigned int defaultunderline = 7;
/* /*
* Internal mouse shortcuts. * Internal mouse shortcuts.
@ -172,6 +169,7 @@ static Shortcut shortcuts[] = {
{ MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} }, { MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} },
{ MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} }, { MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} },
{ MODKEY, XK_Num_Lock, numlock, {.i = 0} }, { MODKEY, XK_Num_Lock, numlock, {.i = 0} },
{ MODKEY, XK_Control_L, iso14755, {.i = 0} },
}; };
/* /*
@ -281,23 +279,39 @@ static Key key[] = {
{ XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0, 0}, { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0, 0},
{ XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0, 0}, { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0, 0},
{ XK_Up, ShiftMask, "\033[1;2A", 0, 0, 0}, { XK_Up, ShiftMask, "\033[1;2A", 0, 0, 0},
{ XK_Up, ControlMask, "\033[1;5A", 0, 0, 0},
{ XK_Up, Mod1Mask, "\033[1;3A", 0, 0, 0}, { XK_Up, Mod1Mask, "\033[1;3A", 0, 0, 0},
{ XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0, 0},
{ XK_Up, ControlMask, "\033[1;5A", 0, 0, 0},
{ XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0, 0},
{ XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0, 0},
{ XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0, 0},
{ XK_Up, XK_ANY_MOD, "\033[A", 0, -1, 0}, { XK_Up, XK_ANY_MOD, "\033[A", 0, -1, 0},
{ XK_Up, XK_ANY_MOD, "\033OA", 0, +1, 0}, { XK_Up, XK_ANY_MOD, "\033OA", 0, +1, 0},
{ XK_Down, ShiftMask, "\033[1;2B", 0, 0, 0}, { XK_Down, ShiftMask, "\033[1;2B", 0, 0, 0},
{ XK_Down, ControlMask, "\033[1;5B", 0, 0, 0},
{ XK_Down, Mod1Mask, "\033[1;3B", 0, 0, 0}, { XK_Down, Mod1Mask, "\033[1;3B", 0, 0, 0},
{ XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0, 0},
{ XK_Down, ControlMask, "\033[1;5B", 0, 0, 0},
{ XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0, 0},
{ XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0, 0},
{ XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0, 0},
{ XK_Down, XK_ANY_MOD, "\033[B", 0, -1, 0}, { XK_Down, XK_ANY_MOD, "\033[B", 0, -1, 0},
{ XK_Down, XK_ANY_MOD, "\033OB", 0, +1, 0}, { XK_Down, XK_ANY_MOD, "\033OB", 0, +1, 0},
{ XK_Left, ShiftMask, "\033[1;2D", 0, 0, 0}, { XK_Left, ShiftMask, "\033[1;2D", 0, 0, 0},
{ XK_Left, ControlMask, "\033[1;5D", 0, 0, 0},
{ XK_Left, Mod1Mask, "\033[1;3D", 0, 0, 0}, { XK_Left, Mod1Mask, "\033[1;3D", 0, 0, 0},
{ XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0, 0},
{ XK_Left, ControlMask, "\033[1;5D", 0, 0, 0},
{ XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0, 0},
{ XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0, 0},
{ XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0, 0},
{ XK_Left, XK_ANY_MOD, "\033[D", 0, -1, 0}, { XK_Left, XK_ANY_MOD, "\033[D", 0, -1, 0},
{ XK_Left, XK_ANY_MOD, "\033OD", 0, +1, 0}, { XK_Left, XK_ANY_MOD, "\033OD", 0, +1, 0},
{ XK_Right, ShiftMask, "\033[1;2C", 0, 0, 0}, { XK_Right, ShiftMask, "\033[1;2C", 0, 0, 0},
{ XK_Right, ControlMask, "\033[1;5C", 0, 0, 0},
{ XK_Right, Mod1Mask, "\033[1;3C", 0, 0, 0}, { XK_Right, Mod1Mask, "\033[1;3C", 0, 0, 0},
{ XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0, 0},
{ XK_Right, ControlMask, "\033[1;5C", 0, 0, 0},
{ XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0, 0},
{ XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0, 0},
{ XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0, 0},
{ XK_Right, XK_ANY_MOD, "\033[C", 0, -1, 0}, { XK_Right, XK_ANY_MOD, "\033[C", 0, -1, 0},
{ XK_Right, XK_ANY_MOD, "\033OC", 0, +1, 0}, { XK_Right, XK_ANY_MOD, "\033OC", 0, +1, 0},
{ XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0, 0}, { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0, 0},

458
config.h Normal file
View File

@ -0,0 +1,458 @@
/* See LICENSE file for copyright and license details. */
/*
* appearance
*
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/
static char font[] = "Inconsolata:size=10:antialias=true:hinting=true";
static int borderpx = 2;
/*
* What program is execed by st depends of these precedence rules:
* 1: program passed with -e
* 2: utmp option
* 3: SHELL environment variable
* 4: value of shell in /etc/passwd
* 5: value of shell in config.h
*/
static char shell[] = "/bin/sh";
static char *utmp = NULL;
static char stty_args[] = "stty raw pass8 nl -echo -iexten -cstopb 38400";
/* identification sequence returned in DA and DECID */
static char vtiden[] = "\033[?6c";
/* Kerning / character bounding-box multipliers */
static float cwscale = 1.0;
static float chscale = 1.0;
/*
* word delimiter string
*
* More advanced example: " `'\"()[]{}"
*/
static char worddelimiters[] = " │`'\"()[]{}";
/* selection timeouts (in milliseconds) */
static unsigned int doubleclicktimeout = 300;
static unsigned int tripleclicktimeout = 600;
/* alt screens */
static int allowaltscreen = 1;
/* frames per second st should at maximum draw to the screen */
static unsigned int xfps = 120;
static unsigned int actionfps = 30;
/*
* blinking timeout (set to 0 to disable blinking) for the terminal blinking
* attribute.
*/
static unsigned int blinktimeout = 800;
/*
* thickness of underline and bar cursors
*/
static unsigned int cursorthickness = 2;
/*
* bell volume. It must be a value between -100 and 100. Use 0 for disabling
* it
*/
static int bellvolume = 0;
/* default TERM value */
static char termname[] = "st-256color";
/*
* spaces per tab
*
* When you are changing this value, don't forget to adapt the »it« value in
* the st.info and appropriately install the st.info in the environment where
* you use this st version.
*
* it#$tabspaces,
*
* Secondly make sure your kernel is not expanding tabs. When running `stty
* -a` »tab0« should appear. You can tell the terminal to not expand tabs by
* running following command:
*
* stty tabs
*/
static unsigned int tabspaces = 4;
/* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = {
/* solarized dark */
"#03171d", /* 0: black */
"#dc322f", /* 1: red */
"#859900", /* 2: green */
"#b58900", /* 3: yellow */
"#268bd2", /* 4: blue */
"#d33682", /* 5: magenta */
"#2aa198", /* 6: cyan */
"#eee8d5", /* 7: white */
"#001014", /* 8: brblack */
"#cb4b16", /* 9: brred */
"#586e75", /* 10: brgreen */
"#657b83", /* 11: bryellow */
"#839496", /* 12: brblue */
"#6c71c4", /* 13: brmagenta*/
"#93a1a1", /* 14: brcyan */
"#fdf6e3", /* 15: brwhite */
};
/*
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
*/
static unsigned int defaultfg = 12;
static unsigned int defaultbg = 8;
static unsigned int defaultcs = 14;
static unsigned int defaultrcs = 15;
/*
* Default shape of cursor
* 2: Block ("█")
* 4: Underline ("_")
* 6: Bar ("|")
* 7: Snowman ("☃")
*/
static unsigned int cursorshape = 2;
/*
* Default columns and rows numbers
*/
static unsigned int cols = 80;
static unsigned int rows = 24;
/*
* Default colour and shape of the mouse cursor
*/
static unsigned int mouseshape = XC_xterm;
static unsigned int mousefg = 7;
static unsigned int mousebg = 0;
/*
* Color used to display font attributes when fontconfig selected a font which
* doesn't match the ones requested.
*/
static unsigned int defaultattr = 11;
/*
* Internal mouse shortcuts.
* Beware that overloading Button1 will disable the selection.
*/
static MouseShortcut mshortcuts[] = {
/* button mask string */
{ Button4, XK_ANY_MOD, "\031" },
{ Button5, XK_ANY_MOD, "\005" },
};
/* Internal keyboard shortcuts. */
#define MODKEY Mod1Mask
static Shortcut shortcuts[] = {
/* mask keysym function argument */
{ XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
{ ControlMask, XK_Print, toggleprinter, {.i = 0} },
{ ShiftMask, XK_Print, printscreen, {.i = 0} },
{ XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
{ MODKEY|ShiftMask, XK_Prior, xzoom, {.f = +2} },
{ MODKEY|ShiftMask, XK_Next, xzoom, {.f = -2} },
{ MODKEY|ShiftMask, XK_Home, xzoomreset, {.f = 0} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ MODKEY|ShiftMask, XK_Insert, clippaste, {.i = 0} },
{ MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} },
{ MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} },
{ MODKEY, XK_Num_Lock, numlock, {.i = 0} },
{ MODKEY, XK_Control_L, iso14755, {.i = 0} },
};
/*
* Special keys (change & recompile st.info accordingly)
*
* Mask value:
* * Use XK_ANY_MOD to match the key no matter modifiers state
* * Use XK_NO_MOD to match the key alone (no modifiers)
* appkey value:
* * 0: no value
* * > 0: keypad application mode enabled
* * = 2: term.numlock = 1
* * < 0: keypad application mode disabled
* appcursor value:
* * 0: no value
* * > 0: cursor application mode enabled
* * < 0: cursor application mode disabled
* crlf value
* * 0: no value
* * > 0: crlf mode is enabled
* * < 0: crlf mode is disabled
*
* Be careful with the order of the definitions because st searches in
* this table sequentially, so any XK_ANY_MOD must be in the last
* position for a key.
*/
/*
* If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
* to be mapped below, add them to this array.
*/
static KeySym mappedkeys[] = { -1 };
/*
* State bits to ignore when matching key or button events. By default,
* numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored.
*/
static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
/*
* Override mouse-select while mask is active (when MODE_MOUSE is set).
* Note that if you want to use ShiftMask with selmasks, set this to an other
* modifier, set to 0 to not use it.
*/
static uint forceselmod = ShiftMask;
/*
* This is the huge key array which defines all compatibility to the Linux
* world. Please decide about changes wisely.
*/
static Key key[] = {
/* keysym mask string appkey appcursor crlf */
{ XK_KP_Home, ShiftMask, "\033[2J", 0, -1, 0},
{ XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1, 0},
{ XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1, 0},
{ XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1, 0},
{ XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0, 0},
{ XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1, 0},
{ XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1, 0},
{ XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0, 0},
{ XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1, 0},
{ XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1, 0},
{ XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0, 0},
{ XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1, 0},
{ XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1, 0},
{ XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0, 0},
{ XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1, 0},
{ XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1, 0},
{ XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0, 0},
{ XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0, 0},
{ XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0, 0},
{ XK_KP_End, ControlMask, "\033[J", -1, 0, 0},
{ XK_KP_End, ControlMask, "\033[1;5F", +1, 0, 0},
{ XK_KP_End, ShiftMask, "\033[K", -1, 0, 0},
{ XK_KP_End, ShiftMask, "\033[1;2F", +1, 0, 0},
{ XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0, 0},
{ XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0, 0},
{ XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0, 0},
{ XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0, 0},
{ XK_KP_Insert, ShiftMask, "\033[4l", -1, 0, 0},
{ XK_KP_Insert, ControlMask, "\033[L", -1, 0, 0},
{ XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0, 0},
{ XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0, 0},
{ XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0, 0},
{ XK_KP_Delete, ControlMask, "\033[M", -1, 0, 0},
{ XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0, 0},
{ XK_KP_Delete, ShiftMask, "\033[2K", -1, 0, 0},
{ XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0, 0},
{ XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0},
{ XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0},
{ XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0, 0},
{ XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0, 0},
{ XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0, 0},
{ XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0, -1},
{ XK_KP_Enter, XK_ANY_MOD, "\r\n", -1, 0, +1},
{ XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0, 0},
{ XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0, 0},
{ XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0, 0},
{ XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0, 0},
{ XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0, 0},
{ XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0, 0},
{ XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0, 0},
{ XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0, 0},
{ XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0, 0},
{ XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0, 0},
{ XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0, 0},
{ XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0, 0},
{ XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0, 0},
{ XK_Up, ShiftMask, "\033[1;2A", 0, 0, 0},
{ XK_Up, Mod1Mask, "\033[1;3A", 0, 0, 0},
{ XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0, 0},
{ XK_Up, ControlMask, "\033[1;5A", 0, 0, 0},
{ XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0, 0},
{ XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0, 0},
{ XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0, 0},
{ XK_Up, XK_ANY_MOD, "\033[A", 0, -1, 0},
{ XK_Up, XK_ANY_MOD, "\033OA", 0, +1, 0},
{ XK_Down, ShiftMask, "\033[1;2B", 0, 0, 0},
{ XK_Down, Mod1Mask, "\033[1;3B", 0, 0, 0},
{ XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0, 0},
{ XK_Down, ControlMask, "\033[1;5B", 0, 0, 0},
{ XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0, 0},
{ XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0, 0},
{ XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0, 0},
{ XK_Down, XK_ANY_MOD, "\033[B", 0, -1, 0},
{ XK_Down, XK_ANY_MOD, "\033OB", 0, +1, 0},
{ XK_Left, ShiftMask, "\033[1;2D", 0, 0, 0},
{ XK_Left, Mod1Mask, "\033[1;3D", 0, 0, 0},
{ XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0, 0},
{ XK_Left, ControlMask, "\033[1;5D", 0, 0, 0},
{ XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0, 0},
{ XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0, 0},
{ XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0, 0},
{ XK_Left, XK_ANY_MOD, "\033[D", 0, -1, 0},
{ XK_Left, XK_ANY_MOD, "\033OD", 0, +1, 0},
{ XK_Right, ShiftMask, "\033[1;2C", 0, 0, 0},
{ XK_Right, Mod1Mask, "\033[1;3C", 0, 0, 0},
{ XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0, 0},
{ XK_Right, ControlMask, "\033[1;5C", 0, 0, 0},
{ XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0, 0},
{ XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0, 0},
{ XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0, 0},
{ XK_Right, XK_ANY_MOD, "\033[C", 0, -1, 0},
{ XK_Right, XK_ANY_MOD, "\033OC", 0, +1, 0},
{ XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0, 0},
{ XK_Return, Mod1Mask, "\033\r", 0, 0, -1},
{ XK_Return, Mod1Mask, "\033\r\n", 0, 0, +1},
{ XK_Return, XK_ANY_MOD, "\r", 0, 0, -1},
{ XK_Return, XK_ANY_MOD, "\r\n", 0, 0, +1},
{ XK_Insert, ShiftMask, "\033[4l", -1, 0, 0},
{ XK_Insert, ShiftMask, "\033[2;2~", +1, 0, 0},
{ XK_Insert, ControlMask, "\033[L", -1, 0, 0},
{ XK_Insert, ControlMask, "\033[2;5~", +1, 0, 0},
{ XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0, 0},
{ XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0, 0},
{ XK_Delete, ControlMask, "\033[M", -1, 0, 0},
{ XK_Delete, ControlMask, "\033[3;5~", +1, 0, 0},
{ XK_Delete, ShiftMask, "\033[2K", -1, 0, 0},
{ XK_Delete, ShiftMask, "\033[3;2~", +1, 0, 0},
{ XK_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0},
{ XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0},
{ XK_BackSpace, XK_NO_MOD, "\177", 0, 0, 0},
{ XK_BackSpace, Mod1Mask, "\033\177", 0, 0, 0},
{ XK_Home, ShiftMask, "\033[2J", 0, -1, 0},
{ XK_Home, ShiftMask, "\033[1;2H", 0, +1, 0},
{ XK_Home, XK_ANY_MOD, "\033[H", 0, -1, 0},
{ XK_Home, XK_ANY_MOD, "\033[1~", 0, +1, 0},
{ XK_End, ControlMask, "\033[J", -1, 0, 0},
{ XK_End, ControlMask, "\033[1;5F", +1, 0, 0},
{ XK_End, ShiftMask, "\033[K", -1, 0, 0},
{ XK_End, ShiftMask, "\033[1;2F", +1, 0, 0},
{ XK_End, XK_ANY_MOD, "\033[4~", 0, 0, 0},
{ XK_Prior, ControlMask, "\033[5;5~", 0, 0, 0},
{ XK_Prior, ShiftMask, "\033[5;2~", 0, 0, 0},
{ XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0, 0},
{ XK_Next, ControlMask, "\033[6;5~", 0, 0, 0},
{ XK_Next, ShiftMask, "\033[6;2~", 0, 0, 0},
{ XK_Next, XK_ANY_MOD, "\033[6~", 0, 0, 0},
{ XK_F1, XK_NO_MOD, "\033OP" , 0, 0, 0},
{ XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0, 0},
{ XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0, 0},
{ XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0, 0},
{ XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0, 0},
{ XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0, 0},
{ XK_F2, XK_NO_MOD, "\033OQ" , 0, 0, 0},
{ XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0, 0},
{ XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0, 0},
{ XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0, 0},
{ XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0, 0},
{ XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0, 0},
{ XK_F3, XK_NO_MOD, "\033OR" , 0, 0, 0},
{ XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0, 0},
{ XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0, 0},
{ XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0, 0},
{ XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0, 0},
{ XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0, 0},
{ XK_F4, XK_NO_MOD, "\033OS" , 0, 0, 0},
{ XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0, 0},
{ XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0, 0},
{ XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0, 0},
{ XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0, 0},
{ XK_F5, XK_NO_MOD, "\033[15~", 0, 0, 0},
{ XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0, 0},
{ XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0, 0},
{ XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0, 0},
{ XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0, 0},
{ XK_F6, XK_NO_MOD, "\033[17~", 0, 0, 0},
{ XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0, 0},
{ XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0, 0},
{ XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0, 0},
{ XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0, 0},
{ XK_F7, XK_NO_MOD, "\033[18~", 0, 0, 0},
{ XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0, 0},
{ XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0, 0},
{ XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0, 0},
{ XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0, 0},
{ XK_F8, XK_NO_MOD, "\033[19~", 0, 0, 0},
{ XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0, 0},
{ XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0, 0},
{ XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0, 0},
{ XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0, 0},
{ XK_F9, XK_NO_MOD, "\033[20~", 0, 0, 0},
{ XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0, 0},
{ XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0, 0},
{ XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0, 0},
{ XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0, 0},
{ XK_F10, XK_NO_MOD, "\033[21~", 0, 0, 0},
{ XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0, 0},
{ XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0, 0},
{ XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0, 0},
{ XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0, 0},
{ XK_F11, XK_NO_MOD, "\033[23~", 0, 0, 0},
{ XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0, 0},
{ XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0, 0},
{ XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0, 0},
{ XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0, 0},
{ XK_F12, XK_NO_MOD, "\033[24~", 0, 0, 0},
{ XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0, 0},
{ XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0, 0},
{ XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0, 0},
{ XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0, 0},
{ XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0, 0},
{ XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0, 0},
{ XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0, 0},
{ XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0, 0},
{ XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0, 0},
{ XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0, 0},
{ XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0, 0},
{ XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0, 0},
{ XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0, 0},
{ XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0, 0},
{ XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0, 0},
{ XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0, 0},
{ XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0, 0},
{ XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0, 0},
{ XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0, 0},
{ XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0, 0},
{ XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0, 0},
{ XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0, 0},
{ XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0, 0},
{ XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0, 0},
{ XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0, 0},
{ XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0, 0},
{ XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0, 0},
};
/*
* Selection types' masks.
* Use the same masks as usual.
* Button1Mask is always unset, to make masks match between ButtonPress.
* ButtonRelease and MotionNotify.
* If no match is found, regular selection is used.
*/
static uint selmasks[] = {
[SEL_RECTANGULAR] = Mod1Mask,
};
/*
* Printable characters in ASCII, used to estimate the advance width
* of single wide characters.
*/
static char ascii_printable[] =
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~";

12
st.1
View File

@ -96,18 +96,18 @@ use a tty
.I line .I line
instead of a pseudo terminal. instead of a pseudo terminal.
.I line .I line
should be a (pseudo-)serial device (e.g. /dev/ttySO on Linux for serial port should be a (pseudo-)serial device (e.g. /dev/ttyS0 on Linux for serial port
0). 0).
When this flag is given When this flag is given
remaining arguments are used as flags for remaining arguments are used as flags for
.BR stty(1). .BR stty(1).
By default st initializes the serial line to 8 bits, no parity, 1 stop bit By default st initializes the serial line to 8 bits, no parity, 1 stop bit
and a 38400 baud rate. The speed is set by appending it as last argument and a 38400 baud rate. The speed is set by appending it as last argument
(e.g. 'st -l 115200'). Arguments before the last one are (e.g. 'st -l /dev/ttyS0 115200'). Arguments before the last one are
.BR stty(1) .BR stty(1)
flags. If you want to set odd parity on 115200 baud use for example 'st -l flags. If you want to set odd parity on 115200 baud use for example 'st -l
parenb parodd 115200'. Set the number of bits by using for example 'st -l cs7 /dev/ttyS0 parenb parodd 115200'. Set the number of bits by using for
115200'. See example 'st -l /dev/ttyS0 cs7 115200'. See
.BR stty(1) .BR stty(1)
for more arguments and cases. for more arguments and cases.
.TP .TP
@ -162,6 +162,10 @@ Copy the selected text to the clipboard selection.
.TP .TP
.B Alt-Shift-v .B Alt-Shift-v
Paste from the clipboard selection. Paste from the clipboard selection.
.TP
.B Alt-Ctrl
Launch dmenu to enter a unicode codepoint and send the corresponding glyph
to st.
.SH CUSTOMIZATION .SH CUSTOMIZATION
.B st .B st
can be customized by creating a custom config.h and (re)compiling the source can be customized by creating a custom config.h and (re)compiling the source

309
st.c
View File

@ -66,6 +66,7 @@ char *argv0;
#define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) < (b) ? (b) : (a)) #define MAX(a, b) ((a) < (b) ? (b) : (a))
#define LEN(a) (sizeof(a) / sizeof(a)[0]) #define LEN(a) (sizeof(a) / sizeof(a)[0])
#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
#define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define DEFAULT(a, b) (a) = (a) ? (a) : (b)
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
@ -87,6 +88,8 @@ char *argv0;
#define TRUEGREEN(x) (((x) & 0xff00)) #define TRUEGREEN(x) (((x) & 0xff00))
#define TRUEBLUE(x) (((x) & 0xff) << 8) #define TRUEBLUE(x) (((x) & 0xff) << 8)
/* constants */
#define ISO14755CMD "dmenu -w %lu -p codepoint: </dev/null"
enum glyph_attribute { enum glyph_attribute {
ATTR_NULL = 0, ATTR_NULL = 0,
@ -137,6 +140,8 @@ enum term_mode {
MODE_MOUSEMANY = 1 << 18, MODE_MOUSEMANY = 1 << 18,
MODE_BRCKTPASTE = 1 << 19, MODE_BRCKTPASTE = 1 << 19,
MODE_PRINT = 1 << 20, MODE_PRINT = 1 << 20,
MODE_UTF8 = 1 << 21,
MODE_SIXEL = 1 << 22,
MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\ MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
|MODE_MOUSEMANY, |MODE_MOUSEMANY,
}; };
@ -154,10 +159,12 @@ enum charset {
enum escape_state { enum escape_state {
ESC_START = 1, ESC_START = 1,
ESC_CSI = 2, ESC_CSI = 2,
ESC_STR = 4, /* DCS, OSC, PM, APC */ ESC_STR = 4, /* OSC, PM, APC */
ESC_ALTCHARSET = 8, ESC_ALTCHARSET = 8,
ESC_STR_END = 16, /* a final string was encountered */ ESC_STR_END = 16, /* a final string was encountered */
ESC_TEST = 32, /* Enter in test mode */ ESC_TEST = 32, /* Enter in test mode */
ESC_UTF8 = 64,
ESC_DCS =128,
}; };
enum window_state { enum window_state {
@ -260,6 +267,11 @@ typedef struct {
Draw draw; Draw draw;
Visual *vis; Visual *vis;
XSetWindowAttributes attrs; XSetWindowAttributes attrs;
/* Here, we use the term *pointer* to differentiate the cursor
* one sees when hovering the mouse over the terminal from, e.g.,
* a green rectangle where text would be entered. */
Cursor vpointer, bpointer; /* visible and hidden pointers */
int pointerisvisible;
int scr; int scr;
int isfixed; /* is fixed geometry? */ int isfixed; /* is fixed geometry? */
int l, t; /* left and top offset */ int l, t; /* left and top offset */
@ -334,6 +346,7 @@ static void xzoomabs(const Arg *);
static void xzoomreset(const Arg *); static void xzoomreset(const Arg *);
static void printsel(const Arg *); static void printsel(const Arg *);
static void printscreen(const Arg *) ; static void printscreen(const Arg *) ;
static void iso14755(const Arg *);
static void toggleprinter(const Arg *); static void toggleprinter(const Arg *);
static void sendbreak(const Arg *); static void sendbreak(const Arg *);
@ -346,6 +359,8 @@ typedef struct {
int width; int width;
int ascent; int ascent;
int descent; int descent;
int badslant;
int badweight;
short lbearing; short lbearing;
short rbearing; short rbearing;
XftFont *match; XftFont *match;
@ -412,6 +427,7 @@ static void tfulldirt(void);
static void techo(Rune); static void techo(Rune);
static void tcontrolcode(uchar ); static void tcontrolcode(uchar );
static void tdectest(char ); static void tdectest(char );
static void tdefutf8(char);
static int32_t tdefcolor(int *, int *, int); static int32_t tdefcolor(int *, int *, int);
static void tdeftran(char); static void tdeftran(char);
static inline int match(uint, uint); static inline int match(uint, uint);
@ -1263,6 +1279,8 @@ xsetsel(char *str, Time t)
XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
selclear(0); selclear(0);
clipcopy(NULL);
} }
void void
@ -1291,6 +1309,13 @@ bmotion(XEvent *e)
{ {
int oldey, oldex, oldsby, oldsey; int oldey, oldex, oldsby, oldsey;
if(!xw.pointerisvisible) {
XDefineCursor(xw.dpy, xw.win, xw.vpointer);
xw.pointerisvisible = 1;
if(!IS_SET(MODE_MOUSEMANY))
xsetpointermotion(0);
}
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
mousereport(e); mousereport(e);
return; return;
@ -1478,17 +1503,29 @@ ttyread(void)
if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0) if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
die("Couldn't read from shell: %s\n", strerror(errno)); die("Couldn't read from shell: %s\n", strerror(errno));
/* process every complete utf8 char */
buflen += ret; buflen += ret;
ptr = buf; ptr = buf;
while ((charsize = utf8decode(ptr, &unicodep, buflen))) {
tputc(unicodep);
ptr += charsize;
buflen -= charsize;
}
for (;;) {
if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
/* process a complete utf8 char */
charsize = utf8decode(ptr, &unicodep, buflen);
if (charsize == 0)
break;
tputc(unicodep);
ptr += charsize;
buflen -= charsize;
} else {
if (buflen <= 0)
break;
tputc(*ptr++ & 0xFF);
buflen--;
}
}
/* keep any uncomplete utf8 char for the next call */ /* keep any uncomplete utf8 char for the next call */
memmove(buf, ptr, buflen); if (buflen > 0)
memmove(buf, ptr, buflen);
return ret; return ret;
} }
@ -1554,15 +1591,26 @@ void
ttysend(char *s, size_t n) ttysend(char *s, size_t n)
{ {
int len; int len;
char *t, *lim;
Rune u; Rune u;
ttywrite(s, n); ttywrite(s, n);
if (IS_SET(MODE_ECHO)) if (!IS_SET(MODE_ECHO))
while ((len = utf8decode(s, &u, n)) > 0) { return;
techo(u);
n -= len; lim = &s[n];
s += len; for (t = s; t < lim; t += len) {
if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
len = utf8decode(t, &u, n);
} else {
u = *t & 0xFF;
len = 1;
} }
if (len <= 0)
break;
techo(u);
n -= len;
}
} }
void void
@ -1656,7 +1704,7 @@ treset(void)
term.tabs[i] = 1; term.tabs[i] = 1;
term.top = 0; term.top = 0;
term.bot = term.row - 1; term.bot = term.row - 1;
term.mode = MODE_WRAP; term.mode = MODE_WRAP|MODE_UTF8;
memset(term.trantbl, CS_USA, sizeof(term.trantbl)); memset(term.trantbl, CS_USA, sizeof(term.trantbl));
term.charset = 0; term.charset = 0;
@ -2200,11 +2248,12 @@ tsetmode(int priv, int set, int *args, int narg)
MODBIT(term.mode, set, MODE_BRCKTPASTE); MODBIT(term.mode, set, MODE_BRCKTPASTE);
break; break;
/* Not implemented mouse modes. See comments there. */ /* Not implemented mouse modes. See comments there. */
case 1001: /* mouse highlight mode; can hang the
terminal by design when implemented. */
case 1005: /* UTF-8 mouse mode; will confuse case 1005: /* UTF-8 mouse mode; will confuse
applications not supporting UTF-8 applications not supporting UTF-8
and luit. */ and luit. */
break; // so we don't print error message below
case 1001: /* mouse highlight mode; can hang the
terminal by design when implemented. */
case 1015: /* urxvt mangled mouse mode; incompatible case 1015: /* urxvt mangled mouse mode; incompatible
and can be mistaken for other control and can be mistaken for other control
codes. */ codes. */
@ -2456,22 +2505,22 @@ csidump(void)
int i; int i;
uint c; uint c;
printf("ESC["); fprintf(stderr, "ESC[");
for (i = 0; i < csiescseq.len; i++) { for (i = 0; i < csiescseq.len; i++) {
c = csiescseq.buf[i] & 0xff; c = csiescseq.buf[i] & 0xff;
if (isprint(c)) { if (isprint(c)) {
putchar(c); putc(c, stderr);
} else if (c == '\n') { } else if (c == '\n') {
printf("(\\n)"); fprintf(stderr, "(\\n)");
} else if (c == '\r') { } else if (c == '\r') {
printf("(\\r)"); fprintf(stderr, "(\\r)");
} else if (c == 0x1b) { } else if (c == 0x1b) {
printf("(\\e)"); fprintf(stderr, "(\\e)");
} else { } else {
printf("(%02x)", c); fprintf(stderr, "(%02x)", c);
} }
} }
putchar('\n'); putc('\n', stderr);
} }
void void
@ -2522,6 +2571,7 @@ strhandle(void)
xsettitle(strescseq.args[0]); xsettitle(strescseq.args[0]);
return; return;
case 'P': /* DCS -- Device Control String */ case 'P': /* DCS -- Device Control String */
term.mode |= ESC_DCS;
case '_': /* APC -- Application Program Command */ case '_': /* APC -- Application Program Command */
case '^': /* PM -- Privacy Message */ case '^': /* PM -- Privacy Message */
return; return;
@ -2559,24 +2609,25 @@ strdump(void)
int i; int i;
uint c; uint c;
printf("ESC%c", strescseq.type); fprintf(stderr, "ESC%c", strescseq.type);
for (i = 0; i < strescseq.len; i++) { for (i = 0; i < strescseq.len; i++) {
c = strescseq.buf[i] & 0xff; c = strescseq.buf[i] & 0xff;
if (c == '\0') { if (c == '\0') {
putc('\n', stderr);
return; return;
} else if (isprint(c)) { } else if (isprint(c)) {
putchar(c); putc(c, stderr);
} else if (c == '\n') { } else if (c == '\n') {
printf("(\\n)"); fprintf(stderr, "(\\n)");
} else if (c == '\r') { } else if (c == '\r') {
printf("(\\r)"); fprintf(stderr, "(\\r)");
} else if (c == 0x1b) { } else if (c == 0x1b) {
printf("(\\e)"); fprintf(stderr, "(\\e)");
} else { } else {
printf("(%02x)", c); fprintf(stderr, "(%02x)", c);
} }
} }
printf("ESC\\\n"); fprintf(stderr, "ESC\\\n");
} }
void void
@ -2603,6 +2654,30 @@ tprinter(char *s, size_t len)
} }
} }
void
iso14755(const Arg *arg)
{
char cmd[sizeof(ISO14755CMD) + NUMMAXLEN(xw.win)];
FILE *p;
char *us, *e, codepoint[9], uc[UTF_SIZ];
unsigned long utf32;
snprintf(cmd, sizeof(cmd), ISO14755CMD, xw.win);
if (!(p = popen(cmd, "r")))
return;
us = fgets(codepoint, sizeof(codepoint), p);
pclose(p);
if (!us || *us == '\0' || *us == '-' || strlen(us) > 7)
return;
if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX ||
(*e != '\n' && *e != '\0'))
return;
ttysend(uc, utf8encode(utf32, uc));
}
void void
toggleprinter(const Arg *arg) toggleprinter(const Arg *arg)
{ {
@ -2689,6 +2764,15 @@ techo(Rune u)
tputc(u); tputc(u);
} }
void
tdefutf8(char ascii)
{
if (ascii == 'G')
term.mode |= MODE_UTF8;
else if (ascii == '@')
term.mode &= ~MODE_UTF8;
}
void void
tdeftran(char ascii) tdeftran(char ascii)
{ {
@ -2719,9 +2803,12 @@ tdectest(char c)
void void
tstrsequence(uchar c) tstrsequence(uchar c)
{ {
strreset();
switch (c) { switch (c) {
case 0x90: /* DCS -- Device Control String */ case 0x90: /* DCS -- Device Control String */
c = 'P'; c = 'P';
term.esc |= ESC_DCS;
break; break;
case 0x9f: /* APC -- Application Program Command */ case 0x9f: /* APC -- Application Program Command */
c = '_'; c = '_';
@ -2733,7 +2820,6 @@ tstrsequence(uchar c)
c = ']'; c = ']';
break; break;
} }
strreset();
strescseq.type = c; strescseq.type = c;
term.esc |= ESC_STR; term.esc |= ESC_STR;
} }
@ -2851,6 +2937,9 @@ eschandle(uchar ascii)
case '#': case '#':
term.esc |= ESC_TEST; term.esc |= ESC_TEST;
return 0; return 0;
case '%':
term.esc |= ESC_UTF8;
return 0;
case 'P': /* DCS -- Device Control String */ case 'P': /* DCS -- Device Control String */
case '_': /* APC -- Application Program Command */ case '_': /* APC -- Application Program Command */
case '^': /* PM -- Privacy Message */ case '^': /* PM -- Privacy Message */
@ -2930,10 +3019,15 @@ tputc(Rune u)
Glyph *gp; Glyph *gp;
control = ISCONTROL(u); control = ISCONTROL(u);
len = utf8encode(u, c); if (!IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
if (!control && (width = wcwidth(u)) == -1) { c[0] = u;
memcpy(c, "\357\277\275", 4); /* UTF_INVALID */ width = len = 1;
width = 1; } else {
len = utf8encode(u, c);
if (!control && (width = wcwidth(u)) == -1) {
memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
width = 1;
}
} }
if (IS_SET(MODE_PRINT)) if (IS_SET(MODE_PRINT))
@ -2948,30 +3042,47 @@ tputc(Rune u)
if (term.esc & ESC_STR) { if (term.esc & ESC_STR) {
if (u == '\a' || u == 030 || u == 032 || u == 033 || if (u == '\a' || u == 030 || u == 032 || u == 033 ||
ISCONTROLC1(u)) { ISCONTROLC1(u)) {
term.esc &= ~(ESC_START|ESC_STR); term.esc &= ~(ESC_START|ESC_STR|ESC_DCS);
if (IS_SET(MODE_SIXEL)) {
/* TODO: render sixel */;
term.mode &= ~MODE_SIXEL;
return;
}
term.esc |= ESC_STR_END; term.esc |= ESC_STR_END;
} else if (strescseq.len + len < sizeof(strescseq.buf) - 1) { goto check_control_code;
memmove(&strescseq.buf[strescseq.len], c, len); }
strescseq.len += len;
return;
} else { if (IS_SET(MODE_SIXEL)) {
/* /* TODO: implement sixel mode */
* Here is a bug in terminals. If the user never sends
* some code to stop the str or esc command, then st
* will stop responding. But this is better than
* silently failing with unknown characters. At least
* then users will report back.
*
* In the case users ever get fixed, here is the code:
*/
/*
* term.esc = 0;
* strhandle();
*/
return; return;
} }
if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q')
term.mode |= MODE_SIXEL;
if (strescseq.len+len >= sizeof(strescseq.buf)-1) {
/*
* Here is a bug in terminals. If the user never sends
* some code to stop the str or esc command, then st
* will stop responding. But this is better than
* silently failing with unknown characters. At least
* then users will report back.
*
* In the case users ever get fixed, here is the code:
*/
/*
* term.esc = 0;
* strhandle();
*/
return;
}
memmove(&strescseq.buf[strescseq.len], c, len);
strescseq.len += len;
return;
} }
check_control_code:
/* /*
* Actions of control codes must be performed as soon they arrive * Actions of control codes must be performed as soon they arrive
* because they can be embedded inside a control sequence, and * because they can be embedded inside a control sequence, and
@ -2994,6 +3105,8 @@ tputc(Rune u)
csihandle(); csihandle();
} }
return; return;
} else if (term.esc & ESC_UTF8) {
tdefutf8(u);
} else if (term.esc & ESC_ALTCHARSET) { } else if (term.esc & ESC_ALTCHARSET) {
tdeftran(u); tdeftran(u);
} else if (term.esc & ESC_TEST) { } else if (term.esc & ESC_TEST) {
@ -3275,25 +3388,64 @@ xgeommasktogravity(int mask)
int int
xloadfont(Font *f, FcPattern *pattern) xloadfont(Font *f, FcPattern *pattern)
{ {
FcPattern *configured;
FcPattern *match; FcPattern *match;
FcResult result; FcResult result;
XGlyphInfo extents; XGlyphInfo extents;
int wantattr, haveattr;
match = XftFontMatch(xw.dpy, xw.scr, pattern, &result); /*
if (!match) * Manually configure instead of calling XftMatchFont
* so that we can use the configured pattern for
* "missing glyph" lookups.
*/
configured = FcPatternDuplicate(pattern);
if (!configured)
return 1; return 1;
FcConfigSubstitute(NULL, configured, FcMatchPattern);
XftDefaultSubstitute(xw.dpy, xw.scr, configured);
match = FcFontMatch(NULL, configured, &result);
if (!match) {
FcPatternDestroy(configured);
return 1;
}
if (!(f->match = XftFontOpenPattern(xw.dpy, match))) { if (!(f->match = XftFontOpenPattern(xw.dpy, match))) {
FcPatternDestroy(configured);
FcPatternDestroy(match); FcPatternDestroy(match);
return 1; return 1;
} }
if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) ==
XftResultMatch)) {
/*
* Check if xft was unable to find a font with the appropriate
* slant but gave us one anyway. Try to mitigate.
*/
if ((XftPatternGetInteger(f->match->pattern, "slant", 0,
&haveattr) != XftResultMatch) || haveattr < wantattr) {
f->badslant = 1;
fputs("st: font slant does not match\n", stderr);
}
}
if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) ==
XftResultMatch)) {
if ((XftPatternGetInteger(f->match->pattern, "weight", 0,
&haveattr) != XftResultMatch) || haveattr != wantattr) {
f->badweight = 1;
fputs("st: font weight does not match\n", stderr);
}
}
XftTextExtentsUtf8(xw.dpy, f->match, XftTextExtentsUtf8(xw.dpy, f->match,
(const FcChar8 *) ascii_printable, (const FcChar8 *) ascii_printable,
strlen(ascii_printable), &extents); strlen(ascii_printable), &extents);
f->set = NULL; f->set = NULL;
f->pattern = FcPatternDuplicate(pattern); f->pattern = configured;
f->ascent = f->match->ascent; f->ascent = f->match->ascent;
f->descent = f->match->descent; f->descent = f->match->descent;
@ -3435,10 +3587,10 @@ void
xinit(void) xinit(void)
{ {
XGCValues gcvalues; XGCValues gcvalues;
Cursor cursor;
Window parent; Window parent;
pid_t thispid = getpid(); pid_t thispid = getpid();
XColor xmousefg, xmousebg; XColor xmousefg, xmousebg;
Pixmap blankpm;
if (!(xw.dpy = XOpenDisplay(NULL))) if (!(xw.dpy = XOpenDisplay(NULL)))
die("Can't open display\n"); die("Can't open display\n");
@ -3511,8 +3663,9 @@ xinit(void)
die("XCreateIC failed. Could not obtain input method.\n"); die("XCreateIC failed. Could not obtain input method.\n");
/* white cursor, black outline */ /* white cursor, black outline */
cursor = XCreateFontCursor(xw.dpy, mouseshape); xw.pointerisvisible = 1;
XDefineCursor(xw.dpy, xw.win, cursor); xw.vpointer = XCreateFontCursor(xw.dpy, mouseshape);
XDefineCursor(xw.dpy, xw.win, xw.vpointer);
if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) { if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) {
xmousefg.red = 0xffff; xmousefg.red = 0xffff;
@ -3526,7 +3679,10 @@ xinit(void)
xmousebg.blue = 0x0000; xmousebg.blue = 0x0000;
} }
XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg); XRecolorCursor(xw.dpy, xw.vpointer, &xmousefg, &xmousebg);
blankpm = XCreateBitmapFromData(xw.dpy, xw.win, &(char){0}, 1, 1);
xw.bpointer = XCreatePixmapCursor(xw.dpy, blankpm, blankpm,
&xmousefg, &xmousebg, 0, 0);
xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
@ -3575,13 +3731,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
frcflags = FRC_NORMAL; frcflags = FRC_NORMAL;
runewidth = xw.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f); runewidth = xw.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f);
if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
font = &dc.ibfont; font = &dc.ifont;
frcflags = FRC_ITALICBOLD; frcflags = FRC_ITALICBOLD;
} else if (mode & ATTR_ITALIC) { } else if (mode & ATTR_ITALIC) {
font = &dc.ifont; font = &dc.ifont;
frcflags = FRC_ITALIC; frcflags = FRC_ITALIC;
} else if (mode & ATTR_BOLD) { } else if (mode & ATTR_BOLD) {
font = &dc.bfont; font = &dc.font;
frcflags = FRC_BOLD; frcflags = FRC_BOLD;
} }
yp = winy + font->ascent; yp = winy + font->ascent;
@ -3685,14 +3841,13 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
XRenderColor colfg, colbg; XRenderColor colfg, colbg;
XRectangle r; XRectangle r;
/* Determine foreground and background colors based on mode. */ /* Fallback on color display for attributes not supported by the font */
if (base.fg == defaultfg) { if (base.mode & ATTR_ITALIC && base.mode & ATTR_BOLD) {
if (base.mode & ATTR_ITALIC) if (dc.ibfont.badslant || dc.ibfont.badweight)
base.fg = defaultitalic; base.fg = defaultattr;
else if ((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) } else if ((base.mode & ATTR_ITALIC && dc.ifont.badslant) ||
base.fg = defaultitalic; (base.mode & ATTR_BOLD && dc.bfont.badweight)) {
else if (base.mode & ATTR_UNDERLINE) base.fg = defaultattr;
base.fg = defaultunderline;
} }
if (IS_TRUECOL(base.fg)) { if (IS_TRUECOL(base.fg)) {
@ -3719,7 +3874,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
/* Change basic system colors [0-7] to bright system colors [8-15] */ /* Change basic system colors [0-7] to bright system colors [8-15] */
if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7)) if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7))
fg = &dc.col[base.fg + 8]; fg = &dc.col[base.fg];
if (IS_SET(MODE_REVERSE)) { if (IS_SET(MODE_REVERSE)) {
if (fg == &dc.col[defaultfg]) { if (fg == &dc.col[defaultfg]) {
@ -4026,6 +4181,8 @@ unmap(XEvent *ev)
void void
xsetpointermotion(int set) xsetpointermotion(int set)
{ {
if(!set && !xw.pointerisvisible)
return;
MODBIT(xw.attrs.event_mask, set, PointerMotionMask); MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
} }
@ -4125,6 +4282,12 @@ kpress(XEvent *ev)
Status status; Status status;
Shortcut *bp; Shortcut *bp;
if(xw.pointerisvisible) {
XDefineCursor(xw.dpy, xw.win, xw.bpointer);
xsetpointermotion(1);
xw.pointerisvisible = 0;
}
if (IS_SET(MODE_KBDLOCK)) if (IS_SET(MODE_KBDLOCK))
return; return;
@ -4335,8 +4498,6 @@ usage(void)
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
uint cols = 80, rows = 24;
xw.l = xw.t = 0; xw.l = xw.t = 0;
xw.isfixed = False; xw.isfixed = False;
xw.cursor = cursorshape; xw.cursor = cursorshape;

View File

@ -149,7 +149,6 @@ st| simpleterm,
lines#24, lines#24,
mir, mir,
msgr, msgr,
ncv#3,
npc, npc,
op=\E[39;49m, op=\E[39;49m,
pairs#64, pairs#64,
@ -186,7 +185,10 @@ st| simpleterm,
tsl=\E]0;, tsl=\E]0;,
xenl, xenl,
vpa=\E[%i%p1%dd, vpa=\E[%i%p1%dd,
# Tmux unofficial extensions, see TERMINFO EXTENSIONS in tmux(1)
Se,
Ss,
Tc,
st-256color| simpleterm with 256 colors, st-256color| simpleterm with 256 colors,
use=st, use=st,