|
|
|
|
/* See LICENSE for license details. */
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <locale.h>
|
|
|
|
|
#include <pwd.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
#include <sys/select.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
#include <termios.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <libgen.h>
|
|
|
|
|
#include <fontconfig/fontconfig.h>
|
|
|
|
|
#include <wchar.h>
|
|
|
|
|
|
|
|
|
|
/* X11 */
|
|
|
|
|
#include <X11/cursorfont.h>
|
|
|
|
|
#include <X11/Xft/Xft.h>
|
|
|
|
|
|
|
|
|
|
char *argv0;
|
|
|
|
|
|
|
|
|
|
#define Glyph Glyph_
|
|
|
|
|
#define Font Font_
|
|
|
|
|
|
|
|
|
|
#include "win.h"
|
|
|
|
|
#include "st.h"
|
|
|
|
|
|
|
|
|
|
#if defined(__linux)
|
|
|
|
|
#include <pty.h>
|
|
|
|
|
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
|
|
|
|
#include <util.h>
|
|
|
|
|
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
|
|
|
|
#include <libutil.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Arbitrary sizes */
|
|
|
|
|
#define UTF_INVALID 0xFFFD
|
|
|
|
|
#define ESC_BUF_SIZ (128*UTF_SIZ)
|
|
|
|
|
#define ESC_ARG_SIZ 16
|
|
|
|
|
#define STR_BUF_SIZ ESC_BUF_SIZ
|
|
|
|
|
#define STR_ARG_SIZ ESC_ARG_SIZ
|
|
|
|
|
|
|
|
|
|
/* macros */
|
|
|
|
|
#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
|
|
|
|
|
#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
|
|
|
|
|
#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177')
|
|
|
|
|
#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
|
|
|
|
|
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
|
|
|
|
|
#define ISDELIM(u) (utf8strchr(worddelimiters, u) != NULL)
|
|
|
|
|
|
|
|
|
|
/* constants */
|
|
|
|
|
#define ISO14755CMD "dmenu -w %lu -p codepoint: </dev/null"
|
|
|
|
|
|
|
|
|
|
enum cursor_movement {
|
|
|
|
|
CURSOR_SAVE,
|
|
|
|
|
CURSOR_LOAD
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum cursor_state {
|
|
|
|
|
CURSOR_DEFAULT = 0,
|
|
|
|
|
CURSOR_WRAPNEXT = 1,
|
|
|
|
|
CURSOR_ORIGIN = 2
|
|
|
|
|
};
|
|
|
|
|
|
Add support for multiple charset definitions
vt100 has support for two defined charset, G0 and G1. Each charset
can be defined, but in each moment is selected only one of both
charset. This is usually used selecting a national charset in G0
and graphic charset in G1, so you can switch between graphic
charset and text charset without losing the national charset
already defined.
st hasn't support for national charsets, because it is an utf8
based terminal emulator, but it has support for graphic
charset because it is heavily used, but it only supports G0,
without understanding G1 selection sequences, which causes some
programs in some moments can print some garbage in the screen.
This patch adds a fake support for multiple charset definitions,
where we only support graphic charset and us-ascii charset, but
we allow more of one charset definition.
This patch allow define G0 until G3 charsets, but only accepts
select G0 or G1, and it accepts some national charset definitions
but all of them are mapped to us-ascii.
9 years ago
|
|
|
|
enum charset {
|
|
|
|
|
CS_GRAPHIC0,
|
|
|
|
|
CS_GRAPHIC1,
|
|
|
|
|
CS_UK,
|
|
|
|
|
CS_USA,
|
|
|
|
|
CS_MULTI,
|
|
|
|
|
CS_GER,
|
|
|
|
|
CS_FIN
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum escape_state {
|
|
|
|
|
ESC_START = 1,
|
|
|
|
|
ESC_CSI = 2,
|
|
|
|
|
ESC_STR = 4, /* OSC, PM, APC */
|
|
|
|
|
ESC_ALTCHARSET = 8,
|
|
|
|
|
ESC_STR_END = 16, /* a final string was encountered */
|
|
|
|
|
ESC_TEST = 32, /* Enter in test mode */
|
|
|
|
|
ESC_UTF8 = 64,
|
|
|
|
|
ESC_DCS =128,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* CSI Escape sequence structs */
|
|
|
|
|
/* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
|
|
|
|
|
typedef struct {
|
|
|
|
|
char buf[ESC_BUF_SIZ]; /* raw string */
|
|
|
|
|
int len; /* raw string length */
|
|
|
|
|
char priv;
|
|
|
|
|
int arg[ESC_ARG_SIZ];
|
|
|
|
|
int narg; /* nb of args */
|
|
|
|
|
char mode[2];
|
|
|
|
|
} CSIEscape;
|
|
|
|
|
|
|
|
|
|
/* STR Escape sequence structs */
|
|
|
|
|
/* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
|
|
|
|
|
typedef struct {
|
|
|
|
|
char type; /* ESC type ... */
|
|
|
|
|
char buf[STR_BUF_SIZ]; /* raw string */
|
|
|
|
|
int len; /* raw string length */
|
|
|
|
|
char *args[STR_ARG_SIZ];
|
|
|
|
|
int narg; /* nb of args */
|
|
|
|
|
} STREscape;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
KeySym k;
|
|
|
|
|
uint mask;
|
|
|
|
|
char *s;
|
|
|
|
|
/* three valued logic variables: 0 indifferent, 1 on, -1 off */
|
|
|
|
|
signed char appkey; /* application keypad */
|
|
|
|
|
signed char appcursor; /* application cursor */
|
|
|
|
|
signed char crlf; /* crlf mode */
|
|
|
|
|
} Key;
|
|
|
|
|
|
|
|
|
|
/* function definitions used in config.h */
|
|
|
|
|
static void clipcopy(const Arg *);
|
|
|
|
|
static void clippaste(const Arg *);
|
|
|
|
|
static void numlock(const Arg *);
|
|
|
|
|
static void selpaste(const Arg *);
|
|
|
|
|
static void zoom(const Arg *);
|
|
|
|
|
static void zoomabs(const Arg *);
|
|
|
|
|
static void zoomreset(const Arg *);
|
|
|
|
|
static void printsel(const Arg *);
|
|
|
|
|
static void printscreen(const Arg *) ;
|
|
|
|
|
static void iso14755(const Arg *);
|
|
|
|
|
static void toggleprinter(const Arg *);
|
|
|
|
|
static void sendbreak(const Arg *);
|
|
|
|
|
|
|
|
|
|
/* config.h for applying patches and the configuration. */
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
static void execsh(void);
|
|
|
|
|
static void stty(void);
|
|
|
|
|
static void sigchld(int);
|
|
|
|
|
|
|
|
|
|
static void csidump(void);
|
|
|
|
|
static void csihandle(void);
|
|
|
|
|
static void csiparse(void);
|
|
|
|
|
static void csireset(void);
|
|
|
|
|
static int eschandle(uchar);
|
|
|
|
|
static void strdump(void);
|
|
|
|
|
static void strhandle(void);
|
|
|
|
|
static void strparse(void);
|
|
|
|
|
static void strreset(void);
|
|
|
|
|
|
|
|
|
|
static void tprinter(char *, size_t);
|
|
|
|
|
static void tdumpsel(void);
|
|
|
|
|
static void tdumpline(int);
|
|
|
|
|
static void tdump(void);
|
|
|
|
|
static void tclearregion(int, int, int, int);
|
|
|
|
|
static void tcursor(int);
|
|
|
|
|
static void tdeletechar(int);
|
|
|
|
|
static void tdeleteline(int);
|
|
|
|
|
static void tinsertblank(int);
|
|
|
|
|
static void tinsertblankline(int);
|
|
|
|
|
static int tlinelen(int);
|
|
|
|
|
static void tmoveto(int, int);
|
|
|
|
|
static void tmoveato(int, int);
|
|
|
|
|
static void tnewline(int);
|
|
|
|
|
static void tputtab(int);
|
|
|
|
|
static void tputc(Rune);
|
|
|
|
|
static void treset(void);
|
|
|
|
|
static void tresize(int, int);
|
|
|
|
|
static void tscrollup(int, int);
|
|
|
|
|
static void tscrolldown(int, int);
|
|
|
|
|
static void tsetattr(int *, int);
|
|
|
|
|
static void tsetchar(Rune, Glyph *, int, int);
|
|
|
|
|
static void tsetscroll(int, int);
|
|
|
|
|
static void tswapscreen(void);
|
|
|
|
|
static void tsetmode(int, int, int *, int);
|
|
|
|
|
static void tfulldirt(void);
|
|
|
|
|
static void techo(Rune);
|
|
|
|
|
static void tcontrolcode(uchar );
|
|
|
|
|
static void tdectest(char );
|
|
|
|
|
static void tdefutf8(char);
|
|
|
|
|
static int32_t tdefcolor(int *, int *, int);
|
Add support for multiple charset definitions
vt100 has support for two defined charset, G0 and G1. Each charset
can be defined, but in each moment is selected only one of both
charset. This is usually used selecting a national charset in G0
and graphic charset in G1, so you can switch between graphic
charset and text charset without losing the national charset
already defined.
st hasn't support for national charsets, because it is an utf8
based terminal emulator, but it has support for graphic
charset because it is heavily used, but it only supports G0,
without understanding G1 selection sequences, which causes some
programs in some moments can print some garbage in the screen.
This patch adds a fake support for multiple charset definitions,
where we only support graphic charset and us-ascii charset, but
we allow more of one charset definition.
This patch allow define G0 until G3 charsets, but only accepts
select G0 or G1, and it accepts some national charset definitions
but all of them are mapped to us-ascii.
9 years ago
|
|
|
|
static void tdeftran(char);
|
|
|
|
|
static void tstrsequence(uchar);
|
|
|
|
|
|
|
|
|
|
static void selscroll(int, int);
|
|
|
|
|
static void selsnap(int *, int *, int);
|
|
|
|
|
|
|
|
|
|
static Rune utf8decodebyte(char, size_t *);
|
|
|
|
|
static char utf8encodebyte(Rune, size_t);
|
|
|
|
|
static char *utf8strchr(char *s, Rune u);
|
|
|
|
|
static size_t utf8validate(Rune *, size_t);
|
|
|
|
|
|
|
|
|
|
static char *base64dec(const char *);
|
|
|
|
|
|
|
|
|
|
static ssize_t xwrite(int, const char *, size_t);
|
|
|
|
|
static void *xrealloc(void *, size_t);
|
|
|
|
|
|
|
|
|
|
/* Globals */
|
|
|
|
|
TermWindow win;
|
|
|
|
|
Term term;
|
|
|
|
|
Selection sel;
|
|
|
|
|
int cmdfd;
|
|
|
|
|
pid_t pid;
|
|
|
|
|
char **opt_cmd = NULL;
|
|
|
|
|
char *opt_class = NULL;
|
|
|
|
|
char *opt_embed = NULL;
|
|
|
|
|
char *opt_font = NULL;
|
|
|
|
|
char *opt_io = NULL;
|
|
|
|
|
char *opt_line = NULL;
|
|
|
|
|
char *opt_name = NULL;
|
|
|
|
|
char *opt_title = NULL;
|
|
|
|
|
int oldbutton = 3; /* button event on startup: 3 = release */
|
|
|
|
|
|
|
|
|
|
static CSIEscape csiescseq;
|
|
|
|
|
static STREscape strescseq;
|
|
|
|
|
static int iofd = 1;
|
|
|
|
|
|
|
|
|
|
char *usedfont = NULL;
|
|
|
|
|
double usedfontsize = 0;
|
|
|
|
|
double defaultfontsize = 0;
|
|
|
|
|
|
|
|
|
|
static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
|
|
|
|
|
static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
|
|
|
|
static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
|
|
|
|
|
static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
|
|
|
|
|
|
|
|
|
/* config.h array lengths */
|
|
|
|
|
size_t colornamelen = LEN(colorname);
|
|
|
|
|
size_t mshortcutslen = LEN(mshortcuts);
|
|
|
|
|
size_t shortcutslen = LEN(shortcuts);
|
|
|
|
|
size_t selmaskslen = LEN(selmasks);
|
|
|
|
|
|
|
|
|
|
ssize_t
|
|
|
|
|
xwrite(int fd, const char *s, size_t len)
|
|
|
|
|
{
|
|
|
|
|
size_t aux = len;
|
|
|
|
|
ssize_t r;
|
|
|
|
|
|
|
|
|
|
while (len > 0) {
|
|
|
|
|
r = write(fd, s, len);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
len -= r;
|
|
|
|
|
s += r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return aux;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
xmalloc(size_t len)
|
|
|
|
|
{
|
|
|
|
|
void *p = malloc(len);
|
|
|
|
|
|
|
|
|
|
if (!p)
|
|
|
|
|
die("Out of memory\n");
|
|
|
|
|
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
xrealloc(void *p, size_t len)
|
|
|
|
|
{
|
|
|
|
|
if ((p = realloc(p, len)) == NULL)
|
|
|
|
|
die("Out of memory\n");
|
|
|
|
|
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
xstrdup(char *s)
|
|
|
|
|
{
|
|
|
|
|
if ((s = strdup(s)) == NULL)
|
|
|
|
|
die("Out of memory\n");
|
|
|
|
|
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
utf8decode(char *c, Rune *u, size_t clen)
|
|
|
|
|
{
|
|
|
|
|
size_t i, j, len, type;
|
|
|
|
|
Rune udecoded;
|
|
|
|
|
|
|
|
|
|
*u = UTF_INVALID;
|
|
|
|
|
if (!clen)
|
|
|
|
|
return 0;
|
|
|
|
|
udecoded = utf8decodebyte(c[0], &len);
|
|
|
|
|
if (!BETWEEN(len, 1, UTF_SIZ))
|
|
|
|
|
return 1;
|
|
|
|
|
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
|
|
|
|
|
udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
|
|
|
|
|
if (type != 0)
|
|
|
|
|
return j;
|
|
|
|
|
}
|
|
|
|
|
if (j < len)
|
|
|
|
|
return 0;
|
|
|
|
|
*u = udecoded;
|
|
|
|
|
utf8validate(u, len);
|
|
|
|
|
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Rune
|
|
|
|
|
utf8decodebyte(char c, size_t *i)
|
|
|
|
|
{
|
|
|
|
|
for (*i = 0; *i < LEN(utfmask); ++(*i))
|
|
|
|
|
if (((uchar)c & utfmask[*i]) == utfbyte[*i])
|
|
|
|
|
return (uchar)c & ~utfmask[*i];
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
utf8encode(Rune u, char *c)
|
|
|
|
|
{
|
|
|
|
|
size_t len, i;
|
|
|
|
|
|
|
|
|
|
len = utf8validate(&u, 0);
|
|
|
|
|
if (len > UTF_SIZ)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
for (i = len - 1; i != 0; --i) {
|
|
|
|
|
c[i] = utf8encodebyte(u, 0);
|
|
|
|
|
u >>= 6;
|
|
|
|
|
}
|
|
|
|
|
c[0] = utf8encodebyte(u, len);
|
|
|
|
|
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char
|
|
|
|
|
utf8encodebyte(Rune u, size_t i)
|
|
|
|
|
{
|
|
|
|
|
return utfbyte[i] | (u & ~utfmask[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
utf8strchr(char *s, Rune u)
|
|
|
|
|
{
|
|
|
|
|
Rune r;
|
|
|
|
|
size_t i, j, len;
|
|
|
|
|
|
|
|
|
|
len = strlen(s);
|
|
|
|
|
for (i = 0, j = 0; i < len; i += j) {
|
|
|
|
|
if (!(j = utf8decode(&s[i], &r, len - i)))
|
|
|
|
|
break;
|
|
|
|
|
if (r == u)
|
|
|
|
|
return &(s[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
utf8validate(Rune *u, size_t i)
|
|
|
|
|
{
|
|
|
|
|
if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
|
|
|
|
|
*u = UTF_INVALID;
|
|
|
|
|
for (i = 1; *u > utfmax[i]; ++i)
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char base64_digits[] = {
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0,
|
|
|
|
|
63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, -1, 0, 0, 0, 0, 1,
|
|
|
|
|
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
|
|
|
|
|
22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34,
|
|
|
|
|
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
base64dec(const char *src)
|
|
|
|
|
{
|
|
|
|
|
size_t in_len = strlen(src);
|
|
|
|
|
char *result, *dst;
|
|
|
|
|
|
|
|
|
|
if (in_len % 4)
|
|
|
|
|
return NULL;
|
|
|
|
|
result = dst = xmalloc(in_len / 4 * 3 + 1);
|
|
|
|
|
while (*src) {
|
|
|
|
|
int a = base64_digits[(unsigned char) *src++];
|
|
|
|
|
int b = base64_digits[(unsigned char) *src++];
|
|
|
|
|
int c = base64_digits[(unsigned char) *src++];
|
|
|
|
|
int d = base64_digits[(unsigned char) *src++];
|
|
|
|
|
|
|
|
|
|
*dst++ = (a << 2) | ((b & 0x30) >> 4);
|
|
|
|
|
if (c == -1)
|
|
|
|
|
break;
|
|
|
|
|
*dst++ = ((b & 0x0f) << 4) | ((c & 0x3c) >> 2);
|
|
|
|
|
if (d == -1)
|
|
|
|
|
break;
|
|
|
|
|
*dst++ = ((c & 0x03) << 6) | d;
|
|
|
|
|
}
|
|
|
|
|
*dst = '\0';
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
selinit(void)
|
|
|
|
|
{
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &sel.tclick1);
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &sel.tclick2);
|
|
|
|
|
sel.mode = SEL_IDLE;
|
|
|
|
|
sel.snap = 0;
|
|
|
|
|
sel.ob.x = -1;
|
|
|
|
|
sel.primary = NULL;
|
|
|
|
|
sel.clipboard = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
x2col(int x)
|
|
|
|
|
{
|
|
|
|
|
x -= borderpx;
|
|
|
|
|
x /= win.cw;
|
|
|
|
|
|
|
|
|
|
return LIMIT(x, 0, term.col-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
y2row(int y)
|
|
|
|
|
{
|
|
|
|
|
y -= borderpx;
|
|
|
|
|
y /= win.ch;
|
|
|
|
|
|
|
|
|
|
return LIMIT(y, 0, term.row-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
tlinelen(int y)
|
|
|
|
|
{
|
|
|
|
|
int i = term.col;
|
|
|
|
|
|
|
|
|
|
if (term.line[y][i - 1].mode & ATTR_WRAP)
|
|
|
|
|
return i;
|
|
|
|
|
|
|
|
|
|
while (i > 0 && term.line[y][i - 1].u == ' ')
|
|
|
|
|
--i;
|
|
|
|
|
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
selnormalize(void)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (sel.type == SEL_REGULAR && sel.ob.y != sel.oe.y) {
|
|
|
|
|
sel.nb.x = sel.ob.y < sel.oe.y ? sel.ob.x : sel.oe.x;
|
|
|
|
|
sel.ne.x = sel.ob.y < sel.oe.y ? sel.oe.x : sel.ob.x;
|
|
|
|
|
} else {
|
|
|
|
|
sel.nb.x = MIN(sel.ob.x, sel.oe.x);
|
|
|
|
|
sel.ne.x = MAX(sel.ob.x, sel.oe.x);
|
|
|
|
|
}
|
|
|
|
|
sel.nb.y = MIN(sel.ob.y, sel.oe.y);
|
|
|
|
|
sel.ne.y = MAX(sel.ob.y, sel.oe.y);
|
|
|
|
|
|
|
|
|
|
selsnap(&sel.nb.x, &sel.nb.y, -1);
|
|
|
|
|
selsnap(&sel.ne.x, &sel.ne.y, +1);
|
|
|
|
|
|
|
|
|
|
/* expand selection over line breaks */
|
|
|
|
|
if (sel.type == SEL_RECTANGULAR)
|
|
|
|
|
return;
|
|
|
|
|
i = tlinelen(sel.nb.y);
|
|
|
|
|
if (i < sel.nb.x)
|
|
|
|
|
sel.nb.x = i;
|
|
|
|
|
if (tlinelen(sel.ne.y) <= sel.ne.x)
|
|
|
|
|
sel.ne.x = term.col - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
selected(int x, int y)
|
|
|
|
|
{
|
|
|
|
|
if (sel.mode == SEL_EMPTY)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (sel.type == SEL_RECTANGULAR)
|
|
|
|
|
return BETWEEN(y, sel.nb.y, sel.ne.y)
|
|
|
|
|
&& BETWEEN(x, sel.nb.x, sel.ne.x);
|
|
|
|
|
|
|
|
|
|
return BETWEEN(y, sel.nb.y, sel.ne.y)
|
|
|
|
|
&& (y != sel.nb.y || x >= sel.nb.x)
|
|
|
|
|
&& (y != sel.ne.y || x <= sel.ne.x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
selsnap(int *x, int *y, int direction)
|
|
|
|
|
{
|
|
|
|
|
int newx, newy, xt, yt;
|
|
|
|
|
int delim, prevdelim;
|
|
|
|
|
Glyph *gp, *prevgp;
|
|
|
|
|
|
|
|
|
|
switch (sel.snap) {
|
|
|
|
|
case SNAP_WORD:
|
|
|
|
|
/*
|
|
|
|
|
* Snap around if the word wraps around at the end or
|
|
|
|
|
* beginning of a line.
|
|
|
|
|
*/
|
|
|
|
|
prevgp = &term.line[*y][*x];
|
|
|
|
|
prevdelim = ISDELIM(prevgp->u);
|
|
|
|
|
for (;;) {
|
|
|
|
|
newx = *x + direction;
|
|
|
|
|
newy = *y;
|
|
|
|
|
if (!BETWEEN(newx, 0, term.col - 1)) {
|
|
|
|
|
newy += direction;
|
|
|
|
|
newx = (newx + term.col) % term.col;
|
|
|
|
|
if (!BETWEEN(newy, 0, term.row - 1))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (direction > 0)
|
|
|
|
|
yt = *y, xt = *x;
|
|
|
|
|
else
|
|
|
|
|
yt = newy, xt = newx;
|
|
|
|
|
if (!(term.line[yt][xt].mode & ATTR_WRAP))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (newx >= tlinelen(newy))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
gp = &term.line[newy][newx];
|
|
|
|
|
delim = ISDELIM(gp->u);
|
|
|
|
|
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
|
|
|
|
|
|| (delim && gp->u != prevgp->u)))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
*x = newx;
|
|
|
|
|
*y = newy;
|
|
|