Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
Jef Roosens | 0a41016245 | |
Jef Roosens | 010fb66cb6 | |
Jef Roosens | 25af8ba5fc | |
Jef Roosens | a13536d0c7 | |
Jef Roosens | 1052dd6244 | |
Jef Roosens | 32184c498c | |
Jef Roosens | b6b60550d2 |
|
@ -0,0 +1 @@
|
|||
IndentWidth: 4
|
|
@ -0,0 +1,34 @@
|
|||
# Upcoming
|
||||
## v1.0
|
||||
* Switched build to CMake
|
||||
* Completely overhauled code structure
|
||||
* Add a desktop entry when installing
|
||||
based on [desktopentry](https://st.suckless.org/patches/desktopentry/)
|
||||
|
||||
## v1.1
|
||||
* Configurable transparency (focused and unfocused)
|
||||
based on [alpha](https://st.suckless.org/patches/alpha/) and
|
||||
[alpha focus highlight](https://st.suckless.org/patches/alpha_focus_highlight/)
|
||||
* Proper resizing (aka don't snap to nearest character size)
|
||||
based on [anysize](https://st.suckless.org/patches/anysize/)
|
||||
* Copy to clipboard on selection
|
||||
based on [one clipboard](https://st.suckless.org/patches/clipboard/)
|
||||
|
||||
## v1.2
|
||||
* Add better/gapless rendering of lines/blocks
|
||||
based on [boxdraw](https://st.suckless.org/patches/boxdraw/)
|
||||
* Add support for multiple fonts
|
||||
based on [font2](https://st.suckless.org/patches/font2/)
|
||||
* Hide cursor when working in the terminal
|
||||
based on [hidecursor](https://st.suckless.org/patches/hidecursor/)
|
||||
|
||||
## v1.3
|
||||
* Add ligature support
|
||||
based on [ligature support](https://st.suckless.org/patches/ligatures/)
|
||||
* Support for multiple color pallets
|
||||
* Paste on right click
|
||||
* Scrollback support
|
||||
* Center lines smaller than max height
|
||||
based on [vertcenter](https://st.suckless.org/patches/vertcenter/)
|
||||
* Visual bell
|
||||
based on [visualbell](https://st.suckless.org/patches/visualbell/)
|
106
Makefile
106
Makefile
|
@ -1,67 +1,39 @@
|
|||
# =====CONFIG=====
|
||||
SRC_DIR := src
|
||||
BUILD_DIR := build
|
||||
RELEASE_DIR := $(BUILD_DIR)/release
|
||||
DEBUG_DIR := $(BUILD_DIR)/debug
|
||||
MINSIZEREL_DIR := $(BUILD_DIR)/min_size_rel
|
||||
BINARY := stj
|
||||
CORES := $(shell nproc --all)
|
||||
PREFIX := /usr/local
|
||||
MANPREFIX := $(PREFIX)/share/man
|
||||
|
||||
|
||||
all: debug
|
||||
.PHONY: all
|
||||
|
||||
|
||||
# Installation & removal
|
||||
# =====INSTALL & UNINSTALL=====
|
||||
install: release
|
||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||
cp -f build/release/stj $(DESTDIR)$(PREFIX)/bin
|
||||
chmod 755 $(DESTDIR)$(PREFIX)/bin/stj
|
||||
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
|
||||
sed "s/VERSION/$(VERSION)/g" < data/stj.1 > $(DESTDIR)$(MANPREFIX)/man1/stj.1
|
||||
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/stj.1
|
||||
tic -sx data/stj.info
|
||||
cp -f data/stj.desktop $(DESTDIR)$(PREFIX)/share/applications
|
||||
@ mkdir -p '$(DESTDIR)$(PREFIX)/bin'
|
||||
@ cp -f '$(RELEASE_DIR)/$(BINARY)' '$(DESTDIR)$(PREFIX)/bin'
|
||||
@ chmod 755 '$(DESTDIR)$(PREFIX)/bin/$(BINARY)'
|
||||
@ mkdir -p '$(DESTDIR)$(MANPREFIX)/man1'
|
||||
@ sed "s/VERSION/$(VERSION)/g" < 'data/stj.1' > '$(DESTDIR)$(MANPREFIX)/man1/$(BINARY).1'
|
||||
@ chmod 644 '$(DESTDIR)$(MANPREFIX)/man1/$(BINARY).1'
|
||||
@ tic -sx 'data/stj.info'
|
||||
@ cp -f 'data/$(BINARY).desktop' '$(DESTDIR)$(PREFIX)/share/applications'
|
||||
.PHONY: install
|
||||
|
||||
uninstall:
|
||||
rm -f $(DESTDIR)$(PREFIX)/bin/stj
|
||||
rm -f $(DESTDIR)$(MANPREFIX)/man1/stj.1
|
||||
rm -f $(DESTDIR)$(PREFIX)/share/applications/stj.desktop
|
||||
@ rm -f '$(DESTDIR)$(PREFIX)/bin/$(BINARY)'
|
||||
@ rm -f '$(DESTDIR)$(MANPREFIX)/man1/$(BINARY).1'
|
||||
@ rm -f '$(DESTDIR)$(PREFIX)/share/applications/$(BINARY).desktop'
|
||||
.PHONY: uninstall
|
||||
|
||||
|
||||
# Full clean
|
||||
clean:
|
||||
@ [ ! -e '$(BINARY)' ] || rm '$(BINARY)'
|
||||
@ rm -rf '$(BUILD_DIR)'
|
||||
.PHONY: clean
|
||||
|
||||
|
||||
# Release
|
||||
run-release: release
|
||||
@ ./'$(RELEASE_DIR)/$(BINARY)'
|
||||
.PHONY: run-release
|
||||
|
||||
release: $(RELEASE_DIR)/Makefile
|
||||
@ make -C '$(RELEASE_DIR)' -j'$(CORES)' && \
|
||||
ln -sf '$(RELEASE_DIR)'/'$(BINARY)' ./'$(BINARY)'
|
||||
.PHONY: release
|
||||
|
||||
$(RELEASE_DIR)/Makefile: $(SRC_DIR)/CMakeLists.txt
|
||||
@ cmake \
|
||||
-H'$(SRC_DIR)' \
|
||||
-B'$(RELEASE_DIR)' \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||
|
||||
clean-release:
|
||||
@ rm -rf '$(RELEASE_DIR)'
|
||||
.PHONY: clean-release
|
||||
|
||||
|
||||
# Debug
|
||||
run-debug: debug
|
||||
@ ./'$(DEBUG_DIR)/$(BINARY)'
|
||||
.PHONY: run-debug
|
||||
|
||||
# =====DEBUG=====
|
||||
debug: $(DEBUG_DIR)/Makefile
|
||||
@ make -C '$(DEBUG_DIR)' -j'$(CORES)' && \
|
||||
ln -sf '$(DEBUG_DIR)/$(BINARY)' ./'$(BINARY)'
|
||||
|
@ -74,6 +46,48 @@ $(DEBUG_DIR)/Makefile: $(SRC_DIR)/CMakeLists.txt
|
|||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||
|
||||
|
||||
# =====RELEASE=====
|
||||
release: $(RELEASE_DIR)/Makefile
|
||||
@ make -C '$(RELEASE_DIR)' -j'$(CORES)' && \
|
||||
ln -sf '$(RELEASE_DIR)'/'$(BINARY)' ./'$(BINARY)'
|
||||
.PHONY: release
|
||||
|
||||
$(RELEASE_DIR)/Makefile: $(SRC_DIR)/CMakeLists.txt
|
||||
@ cmake \
|
||||
-H'$(SRC_DIR)' \
|
||||
-B'$(RELEASE_DIR)' \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
|
||||
|
||||
# =====MINIMUM SIZE RELEASE=====
|
||||
minsizerel: $(MINSIZEREL_DIR)/Makefile
|
||||
@ make -C '$(MINSIZEREL_DIR)' -j'$(CORES)' && \
|
||||
ln -sf '$(MINSIZEREL_DIR)'/'$(BINARY)' ./'$(BINARY)'
|
||||
.PHONY: minsizerel
|
||||
|
||||
$(MINSIZEREL_DIR)/Makefile: $(SRC_DIR)/CMakeLists.txt
|
||||
@ cmake \
|
||||
-H'$(SRC_DIR)' \
|
||||
-B'$(MINSIZEREL_DIR)' \
|
||||
-DCMAKE_BUILD_TYPE=MinSizeRel \
|
||||
|
||||
|
||||
# =====CLEANING=====
|
||||
clean:
|
||||
@ [ ! -e '$(BINARY)' ] || rm '$(BINARY)'
|
||||
@ rm -rf '$(BUILD_DIR)'
|
||||
.PHONY: clean
|
||||
|
||||
clean-release:
|
||||
@ rm -rf '$(RELEASE_DIR)'
|
||||
.PHONY: clean-release
|
||||
|
||||
clean-debug:
|
||||
@ rm -rf '$(DEBUG_DIR)'
|
||||
.PHONY: clean-debug
|
||||
|
||||
|
||||
# =====FORMAT CODE=====
|
||||
format:
|
||||
@ find src/ -iname '*.c' -or -iname '*.h' | xargs clang-format --style=file -i
|
||||
|
|
|
@ -5,27 +5,31 @@ if (NOT CMAKE_BUILD_TYPE)
|
|||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
set(SYSTEM_TYPE x64)
|
||||
|
||||
# =====COMPILER=====
|
||||
|
||||
# =====COMMON SETTINGS=====
|
||||
set(CMAKE_C_COMPILER "clang-11")
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
|
||||
project(stj VERSION 0.1)
|
||||
|
||||
|
||||
# =====COMPILE FLAGS=====
|
||||
add_definitions(-DVERSION="${CMAKE_PROJECT_VERSION}" -D_XOPEN_SOURCE=600)
|
||||
|
||||
# Debug flags
|
||||
# -g flag gets auto-added by CMake for the debug build
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -O0 -march=native")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
|
||||
set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address -pedantic")
|
||||
|
||||
# Release flags
|
||||
# -O3 gets added automatically by CMake
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Werror -march=native -pedantic-errors")
|
||||
# =====BUILD TYPES=====
|
||||
# Debug
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -Wall -O0 -fsanitize=address -fno-omit-frame-pointer")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address -pedantic")
|
||||
|
||||
# Arch doesn't use static libraries
|
||||
if(NOT EXISTS "/etc/arch-release")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -static-libasan")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -static-libasan")
|
||||
endif()
|
||||
|
||||
# Release
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -Werror -pedantic-errors")
|
||||
|
||||
|
||||
# =====EXECUTABLE=====
|
||||
|
@ -39,8 +43,10 @@ add_executable(stj x.c "${st_SRC}" "${main_SRC}")
|
|||
find_package(Freetype 2 REQUIRED)
|
||||
target_include_directories(stj PRIVATE "${FREETYPE_INCLUDE_DIRS}")
|
||||
target_link_libraries(stj PRIVATE "${FREETYPE_LIBRARIES}")
|
||||
target_link_libraries(stj PRIVATE Xft)
|
||||
target_link_libraries(stj PRIVATE Xrender)
|
||||
|
||||
find_package(Fontconfig REQUIRED)
|
||||
find_package(Fontconfig 2 REQUIRED)
|
||||
target_include_directories(stj PRIVATE "${Fontconfig_INCLUDE_DIRS}")
|
||||
target_link_libraries(stj PRIVATE "${Fontconfig_LIBRARIES}")
|
||||
|
||||
|
@ -48,8 +54,9 @@ find_package(X11 REQUIRED)
|
|||
target_include_directories(stj PRIVATE "${X11_INCLUDE_DIR}")
|
||||
target_link_libraries(stj PRIVATE "${X11_LIBRARIES}")
|
||||
|
||||
# Normally provided with clang
|
||||
target_link_libraries(stj PRIVATE m)
|
||||
target_link_libraries(stj PRIVATE rt)
|
||||
# I'm not sure if I actually need this, so keeping it here for reference
|
||||
# target_link_libraries(stj PRIVATE rt)
|
||||
|
||||
target_link_libraries(stj PRIVATE util)
|
||||
target_link_libraries(stj PRIVATE Xft)
|
||||
target_link_libraries(stj PRIVATE Xrender)
|
||||
|
|
160
src/st/st.c
160
src/st/st.c
|
@ -20,6 +20,7 @@
|
|||
#include "../win.h"
|
||||
#include "macros.h"
|
||||
#include "st.h"
|
||||
#include "utf8.h"
|
||||
|
||||
#if defined(__linux)
|
||||
#include <pty.h>
|
||||
|
@ -30,8 +31,6 @@
|
|||
#endif
|
||||
|
||||
/* Arbitrary sizes */
|
||||
#define UTF_INVALID 0xFFFD
|
||||
#define UTF_SIZE 4
|
||||
#define ESC_BUF_SIZ (128 * UTF_SIZE)
|
||||
#define ESC_ARG_SIZ 16
|
||||
#define STR_BUF_SIZ ESC_BUF_SIZ
|
||||
|
@ -205,11 +204,6 @@ static void selnormalize(void);
|
|||
static void selscroll(int, int);
|
||||
static void selsnap(int *, int *, int);
|
||||
|
||||
static size_t utf8decode(const char *, Rune *, size_t);
|
||||
static Rune utf8decodebyte(char, size_t *);
|
||||
static char utf8encodebyte(Rune, size_t);
|
||||
static size_t utf8validate(Rune *, size_t);
|
||||
|
||||
static char *base64dec(const char *);
|
||||
static char base64dec_getc(const char **);
|
||||
|
||||
|
@ -224,114 +218,74 @@ static int iofd = 1;
|
|||
static int cmdfd;
|
||||
static pid_t pid;
|
||||
|
||||
static uchar utfbyte[UTF_SIZE + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
|
||||
static uchar utfmask[UTF_SIZE + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
||||
static Rune utfmin[UTF_SIZE + 1] = {0, 0, 0x80, 0x800, 0x10000};
|
||||
static Rune utfmax[UTF_SIZE + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
||||
|
||||
ssize_t xwrite(int fd, const char *s, size_t len) {
|
||||
size_t aux = len;
|
||||
/**
|
||||
* Same as write, but ensures that all bytes are written to the descriptor
|
||||
* (write sometimes isn't able to write all bytes)
|
||||
*
|
||||
* @param p_file_desc file descriptor to write to; same logic as write
|
||||
* @param p_str char array to write to the file descriptor
|
||||
* @param p_nbytes amount of bytes to write
|
||||
* @return p_nbytes if the write was successful, otherwise return negative error
|
||||
* value of write
|
||||
*/
|
||||
ssize_t xwrite(int p_file_desc, const char *p_str, size_t p_nbytes) {
|
||||
size_t aux = p_nbytes;
|
||||
ssize_t result;
|
||||
|
||||
while (len > 0) {
|
||||
result = write(fd, s, len);
|
||||
while (p_nbytes > 0) {
|
||||
result = write(p_file_desc, p_str, p_nbytes);
|
||||
|
||||
// This means an error occured in write, so it passes the error along
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
len -= result;
|
||||
s += result;
|
||||
p_nbytes -= (size_t)result;
|
||||
p_str += result;
|
||||
}
|
||||
|
||||
return aux;
|
||||
return (ssize_t)aux;
|
||||
}
|
||||
|
||||
// Same as malloc, but stops entire program if malloc fails
|
||||
void *safe_malloc(size_t len) {
|
||||
/**
|
||||
* same as malloc, but kill the program if it fails
|
||||
*
|
||||
* @param p_len bytes to allocate
|
||||
* @return pointer to allocated memory
|
||||
*/
|
||||
void *safe_malloc(size_t p_len) {
|
||||
void *ptr;
|
||||
|
||||
if (!(ptr = malloc(len)))
|
||||
if (!(ptr = malloc(p_len)))
|
||||
die("malloc: %s\n", strerror(errno));
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Same as realloc, but stops entire program if malloc fails
|
||||
void *safe_realloc(void *ptr, size_t len) {
|
||||
if ((ptr = realloc(ptr, len)) == NULL)
|
||||
/**
|
||||
* same as realloc, but kill the program if it fails
|
||||
*
|
||||
* @param p_ptr pointer to re-allocate
|
||||
* @param p_len bytes to re-allocate
|
||||
* @return pointer to re-allocated memory
|
||||
*/
|
||||
void *safe_realloc(void *p_ptr, size_t p_len) {
|
||||
if ((p_ptr = realloc(p_ptr, p_len)) == NULL)
|
||||
die("realloc: %s\n", strerror(errno));
|
||||
|
||||
return ptr;
|
||||
return p_ptr;
|
||||
}
|
||||
|
||||
char *safe_strdup(char *s) {
|
||||
if ((s = strdup(s)) == NULL)
|
||||
/**
|
||||
* same as strdup, but kill the program if it fails
|
||||
*
|
||||
* @param p_str string to copy
|
||||
* @return pointer to copy of original string
|
||||
*/
|
||||
char *safe_strdup(char *p_str) {
|
||||
if ((p_str = strdup(p_str)) == NULL)
|
||||
die("strdup: %s\n", strerror(errno));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
size_t utf8decode(const char *chr, Rune *u, size_t chr_len) {
|
||||
size_t i, j, len, type;
|
||||
Rune udecoded;
|
||||
|
||||
*u = UTF_INVALID;
|
||||
if (!chr_len) // chr_len is 0, so just return 0
|
||||
return 0;
|
||||
|
||||
udecoded = utf8decodebyte(chr[0], &len);
|
||||
if (!BETWEEN(len, 1, UTF_SIZE))
|
||||
return 1;
|
||||
|
||||
for (i = 1, j = 1; i < chr_len && j < len; ++i, ++j) {
|
||||
udecoded = (udecoded << 6) | utf8decodebyte(chr[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_SIZE)
|
||||
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]); }
|
||||
|
||||
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;
|
||||
return p_str;
|
||||
}
|
||||
|
||||
static const char base64_digits[] = {
|
||||
|
@ -1019,7 +973,8 @@ void selscroll(int orig, int n) {
|
|||
if (sel.ob.x == -1)
|
||||
return;
|
||||
|
||||
if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) {
|
||||
if (BETWEEN(sel.nb.y, orig, term.bot) !=
|
||||
BETWEEN(sel.ne.y, orig, term.bot)) {
|
||||
selclear();
|
||||
} else if (BETWEEN(sel.nb.y, orig, term.bot)) {
|
||||
sel.ob.y += n;
|
||||
|
@ -1247,8 +1202,8 @@ void tsetattr(int *attr, int l) {
|
|||
switch (attr[i]) {
|
||||
case 0:
|
||||
term.c.attr.mode &=
|
||||
~(ATTR_BOLD | ATTR_FAINT | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_BLINK |
|
||||
ATTR_REVERSE | ATTR_INVISIBLE | ATTR_STRUCK);
|
||||
~(ATTR_BOLD | ATTR_FAINT | ATTR_ITALIC | ATTR_UNDERLINE |
|
||||
ATTR_BLINK | ATTR_REVERSE | ATTR_INVISIBLE | ATTR_STRUCK);
|
||||
term.c.attr.fg = defaultfg;
|
||||
term.c.attr.bg = defaultbg;
|
||||
break;
|
||||
|
@ -1323,7 +1278,8 @@ void tsetattr(int *attr, int l) {
|
|||
} else if (BETWEEN(attr[i], 100, 107)) {
|
||||
term.c.attr.bg = attr[i] - 100 + 8;
|
||||
} else {
|
||||
fprintf(stderr, "erresc(default): gfx attr %d unknown\n", attr[i]);
|
||||
fprintf(stderr, "erresc(default): gfx attr %d unknown\n",
|
||||
attr[i]);
|
||||
csidump();
|
||||
}
|
||||
break;
|
||||
|
@ -1441,7 +1397,8 @@ void tsetmode(int priv, int set, int *args, int narg) {
|
|||
codes. */
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "erresc: unknown private set/reset mode %d\n", *args);
|
||||
fprintf(stderr, "erresc: unknown private set/reset mode %d\n",
|
||||
*args);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
@ -1619,7 +1576,8 @@ void csihandle(void) {
|
|||
break;
|
||||
case 'X': /* ECH -- Erase <n> char */
|
||||
DEFAULT(csiescseq.arg[0], 1);
|
||||
tclearregion(term.c.x, term.c.y, term.c.x + csiescseq.arg[0] - 1, term.c.y);
|
||||
tclearregion(term.c.x, term.c.y, term.c.x + csiescseq.arg[0] - 1,
|
||||
term.c.y);
|
||||
break;
|
||||
case 'P': /* DCH -- Delete <n> char */
|
||||
DEFAULT(csiescseq.arg[0], 1);
|
||||
|
@ -1641,8 +1599,8 @@ void csihandle(void) {
|
|||
break;
|
||||
case 'n': /* DSR – Device Status Report (cursor position) */
|
||||
if (csiescseq.arg[0] == 6) {
|
||||
len =
|
||||
snprintf(buf, sizeof(buf), "\033[%i;%iR", term.c.y + 1, term.c.x + 1);
|
||||
len = snprintf(buf, sizeof(buf), "\033[%i;%iR", term.c.y + 1,
|
||||
term.c.x + 1);
|
||||
ttywrite(buf, len, 0);
|
||||
}
|
||||
break;
|
||||
|
@ -2108,8 +2066,8 @@ int eschandle(uchar ascii) {
|
|||
strhandle();
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n", (uchar)ascii,
|
||||
isprint(ascii) ? ascii : '.');
|
||||
fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
|
||||
(uchar)ascii, isprint(ascii) ? ascii : '.');
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
|
|
28
src/st/st.h
28
src/st/st.h
|
@ -3,9 +3,12 @@
|
|||
#ifndef ST_H
|
||||
#define ST_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "utf8.h"
|
||||
|
||||
enum glyph_attribute {
|
||||
ATTR_NULL = 0,
|
||||
|
@ -23,28 +26,11 @@ enum glyph_attribute {
|
|||
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
|
||||
};
|
||||
|
||||
enum selection_mode {
|
||||
SEL_IDLE = 0,
|
||||
SEL_EMPTY = 1,
|
||||
SEL_READY = 2
|
||||
};
|
||||
enum selection_mode { SEL_IDLE = 0, SEL_EMPTY = 1, SEL_READY = 2 };
|
||||
|
||||
enum selection_type {
|
||||
SEL_REGULAR = 1,
|
||||
SEL_RECTANGULAR = 2
|
||||
};
|
||||
enum selection_type { SEL_REGULAR = 1, SEL_RECTANGULAR = 2 };
|
||||
|
||||
enum selection_snap {
|
||||
SNAP_WORD = 1,
|
||||
SNAP_LINE = 2
|
||||
};
|
||||
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned short ushort;
|
||||
|
||||
typedef uint_least32_t Rune;
|
||||
enum selection_snap { SNAP_WORD = 1, SNAP_LINE = 2 };
|
||||
|
||||
#define Glyph Glyph_
|
||||
typedef struct {
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned short ushort;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,103 @@
|
|||
#include "utf8.h"
|
||||
#include "macros.h"
|
||||
#include "types.h"
|
||||
|
||||
static uchar utfbyte[UTF_SIZE + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
|
||||
static uchar utfmask[UTF_SIZE + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
||||
static Rune utfmin[UTF_SIZE + 1] = {0, 0, 0x80, 0x800, 0x10000};
|
||||
static Rune utfmax[UTF_SIZE + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
||||
|
||||
/**
|
||||
* Decode a given char array into a utf8 Rune
|
||||
*
|
||||
* @param p_char char array to decode
|
||||
* @param p_rune rune pointer to decode to
|
||||
* @param p_char_len length of the char array
|
||||
* @return size of the decoded rune
|
||||
*/
|
||||
size_t utf8decode(const char *p_char, Rune *p_rune, size_t p_char_len) {
|
||||
size_t decoded_len, type, i;
|
||||
Rune decoded_rune;
|
||||
|
||||
*p_rune = UTF_INVALID;
|
||||
if (!p_char_len) // p_char_len is 0, so just return 0
|
||||
return 0;
|
||||
|
||||
decoded_rune = utf8decodebyte(p_char[0], &decoded_len);
|
||||
if (!BETWEEN(decoded_len, 1, UTF_SIZE))
|
||||
return 1;
|
||||
|
||||
for (i = 1; i < p_char_len && i < decoded_len; ++i) {
|
||||
decoded_rune = (decoded_rune << 6) | utf8decodebyte(p_char[i], &type);
|
||||
|
||||
if (type != 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
if (i < decoded_len)
|
||||
return 0;
|
||||
|
||||
*p_rune = decoded_rune;
|
||||
utf8validate(p_rune, decoded_len);
|
||||
|
||||
return decoded_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a single byte to UTF-8
|
||||
*
|
||||
* @param p_char char to decode
|
||||
* @param p_i counter used in internal for loop
|
||||
* @return decoded rune
|
||||
*/
|
||||
Rune utf8decodebyte(char p_char, size_t *p_i) {
|
||||
for (*p_i = 0; *p_i < LEN(utfmask); ++(*p_i)) {
|
||||
if (((uchar)p_char & utfmask[*p_i]) == utfbyte[*p_i])
|
||||
return (uchar)p_char & ~utfmask[*p_i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a UTF-8 rune
|
||||
*
|
||||
* @param p_rune rune to encode
|
||||
* @param p_char char array to encode to
|
||||
* @return
|
||||
*/
|
||||
size_t utf8encode(Rune p_rune, char *p_char) {
|
||||
size_t len, i;
|
||||
|
||||
len = utf8validate(&p_rune, 0);
|
||||
if (len > UTF_SIZE)
|
||||
return 0;
|
||||
|
||||
for (i = len - 1; i != 0; --i) {
|
||||
p_char[i] = utf8encodebyte(p_rune, 0);
|
||||
p_rune >>= 6;
|
||||
}
|
||||
p_char[0] = utf8encodebyte(p_rune, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
char utf8encodebyte(Rune u, size_t i) { return utfbyte[i] | (u & ~utfmask[i]); }
|
||||
|
||||
/**
|
||||
* Check if a given rune is a valid UTF-8 rune
|
||||
*
|
||||
* @param p_rune rune to validate
|
||||
* @param i
|
||||
*/
|
||||
size_t utf8validate(Rune *p_rune, size_t i) {
|
||||
if (!BETWEEN(*p_rune, utfmin[i], utfmax[i]) ||
|
||||
BETWEEN(*p_rune, 0xD800, 0xDFFF))
|
||||
*p_rune = UTF_INVALID;
|
||||
|
||||
// Count up i until you find a utfmax entry that's greater than *p_rune
|
||||
for (i = 1; *p_rune > utfmax[i]; ++i)
|
||||
;
|
||||
|
||||
return i;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef UTF8_H
|
||||
#define UTF8_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define UTF_INVALID 0xFFFD
|
||||
#define UTF_SIZE 4
|
||||
|
||||
typedef uint_least32_t Rune;
|
||||
|
||||
size_t utf8decode(const char *, Rune *, size_t);
|
||||
Rune utf8decodebyte(char, size_t *);
|
||||
char utf8encodebyte(Rune, size_t);
|
||||
size_t utf8validate(Rune *, size_t);
|
||||
|
||||
#endif
|
55
src/x.c
55
src/x.c
|
@ -379,11 +379,11 @@ void mousereport(XEvent *e) {
|
|||
}
|
||||
|
||||
if (IS_SET(MODE_MOUSESGR)) {
|
||||
len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", button, x + 1, y + 1,
|
||||
e->xbutton.type == ButtonRelease ? 'm' : 'M');
|
||||
len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", button, x + 1,
|
||||
y + 1, e->xbutton.type == ButtonRelease ? 'm' : 'M');
|
||||
} else if (x < 223 && y < 223) {
|
||||
len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", 32 + button, 32 + x + 1,
|
||||
32 + y + 1);
|
||||
len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", 32 + button,
|
||||
32 + x + 1, 32 + y + 1);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
@ -569,8 +569,8 @@ void selrequest(XEvent *e) {
|
|||
if (xsre->target == xa_targets) {
|
||||
/* respond with the supported type */
|
||||
string = xsel.xtarget;
|
||||
XChangeProperty(xsre->display, xsre->requestor, xsre->property, XA_ATOM, 32,
|
||||
PropModeReplace, (uchar *)&string, 1);
|
||||
XChangeProperty(xsre->display, xsre->requestor, xsre->property, XA_ATOM,
|
||||
32, PropModeReplace, (uchar *)&string, 1);
|
||||
xev.property = xsre->property;
|
||||
} else if (xsre->target == xsel.xtarget || xsre->target == XA_STRING) {
|
||||
/*
|
||||
|
@ -583,7 +583,8 @@ void selrequest(XEvent *e) {
|
|||
} else if (xsre->selection == clipboard) {
|
||||
seltext = xsel.clipboard;
|
||||
} else {
|
||||
fprintf(stderr, "Unhandled clipboard selection 0x%lx\n", xsre->selection);
|
||||
fprintf(stderr, "Unhandled clipboard selection 0x%lx\n",
|
||||
xsre->selection);
|
||||
return;
|
||||
}
|
||||
if (seltext != NULL) {
|
||||
|
@ -657,8 +658,8 @@ void xresize(int col, int row) {
|
|||
win.th = row * win.ch;
|
||||
|
||||
XFreePixmap(xw.dpy, xw.buf);
|
||||
xw.buf =
|
||||
XCreatePixmap(xw.dpy, xw.win, win.w, win.h, DefaultDepth(xw.dpy, xw.scr));
|
||||
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||
DefaultDepth(xw.dpy, xw.scr));
|
||||
XftDrawChange(xw.draw, xw.buf);
|
||||
xclear(0, 0, win.w, win.h);
|
||||
|
||||
|
@ -950,12 +951,13 @@ int ximopen(Display *dpy) {
|
|||
fprintf(stderr, "XSetIMValues: "
|
||||
"Could not set XNDestroyCallback.\n");
|
||||
|
||||
xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot, NULL);
|
||||
xw.ime.spotlist =
|
||||
XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot, NULL);
|
||||
|
||||
if (xw.ime.xic == NULL) {
|
||||
xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle,
|
||||
XIMPreeditNothing | XIMStatusNothing, XNClientWindow,
|
||||
xw.win, XNDestroyCallback, &icdestroy, NULL);
|
||||
xw.ime.xic = XCreateIC(
|
||||
xw.ime.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
|
||||
XNClientWindow, xw.win, XNDestroyCallback, &icdestroy, NULL);
|
||||
}
|
||||
if (xw.ime.xic == NULL)
|
||||
fprintf(stderr, "XCreateIC: Could not create input context.\n");
|
||||
|
@ -965,8 +967,8 @@ int ximopen(Display *dpy) {
|
|||
|
||||
void ximinstantiate(Display *dpy, XPointer client, XPointer call) {
|
||||
if (ximopen(dpy))
|
||||
XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, ximinstantiate,
|
||||
NULL);
|
||||
XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
|
||||
ximinstantiate, NULL);
|
||||
}
|
||||
|
||||
void ximdestroy(XIM xim, XPointer client, XPointer call) {
|
||||
|
@ -1033,8 +1035,8 @@ void xinit(int cols, int rows) {
|
|||
memset(&gcvalues, 0, sizeof(gcvalues));
|
||||
gcvalues.graphics_exposures = False;
|
||||
dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, &gcvalues);
|
||||
xw.buf =
|
||||
XCreatePixmap(xw.dpy, xw.win, win.w, win.h, DefaultDepth(xw.dpy, xw.scr));
|
||||
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||
DefaultDepth(xw.dpy, xw.scr));
|
||||
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
|
||||
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
|
||||
|
||||
|
@ -1075,8 +1077,8 @@ void xinit(int cols, int rows) {
|
|||
XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
|
||||
|
||||
xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False);
|
||||
XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, PropModeReplace,
|
||||
(uchar *)&thispid, 1);
|
||||
XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
|
||||
PropModeReplace, (uchar *)&thispid, 1);
|
||||
|
||||
win.mode = MODE_NUMLOCK;
|
||||
resettitle();
|
||||
|
@ -1155,7 +1157,8 @@ int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len,
|
|||
if (glyphidx && frc[f].flags == frcflags)
|
||||
break;
|
||||
/* We got a default font for a not found glyph. */
|
||||
if (!glyphidx && frc[f].flags == frcflags && frc[f].unicodep == rune) {
|
||||
if (!glyphidx && frc[f].flags == frcflags &&
|
||||
frc[f].unicodep == rune) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1310,10 +1313,12 @@ void xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len,
|
|||
/* Intelligent cleaning up of the borders. */
|
||||
if (x == 0) {
|
||||
xclear(0, (y == 0) ? 0 : winy, borderpx,
|
||||
winy + win.ch + ((winy + win.ch >= borderpx + win.th) ? win.h : 0));
|
||||
winy + win.ch +
|
||||
((winy + win.ch >= borderpx + win.th) ? win.h : 0));
|
||||
}
|
||||
if (winx + width >= borderpx + win.tw) {
|
||||
xclear(winx + width, (y == 0) ? 0 : winy, win.w,
|
||||
xclear(
|
||||
winx + width, (y == 0) ? 0 : winy, win.w,
|
||||
((winy + win.ch >= borderpx + win.th) ? win.h : (winy + win.ch)));
|
||||
}
|
||||
if (y == 0)
|
||||
|
@ -1369,7 +1374,8 @@ void xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) {
|
|||
/*
|
||||
* Select the right color for the right mode.
|
||||
*/
|
||||
g.mode &= ATTR_BOLD | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_STRUCK | ATTR_WIDE;
|
||||
g.mode &=
|
||||
ATTR_BOLD | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_STRUCK | ATTR_WIDE;
|
||||
|
||||
if (IS_SET(MODE_REVERSE)) {
|
||||
g.mode |= ATTR_REVERSE;
|
||||
|
@ -1754,7 +1760,8 @@ void run(void) {
|
|||
trigger = now;
|
||||
drawing = 1;
|
||||
}
|
||||
timeout = (maxlatency - TIMEDIFF(now, trigger)) / maxlatency * minlatency;
|
||||
timeout =
|
||||
(maxlatency - TIMEDIFF(now, trigger)) / maxlatency * minlatency;
|
||||
if (timeout > 0)
|
||||
continue; /* we have time, try to find idle */
|
||||
}
|
||||
|
|
Reference in New Issue