From 3ce8459771aee683779211f738adea3abd3aafae Mon Sep 17 00:00:00 2001 From: Andreew Gregory Date: Tue, 7 Oct 2025 17:55:09 +0300 Subject: [PATCH] New dmenu version --- config.def.h | 4 +- dmenuc.py | 126 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 89 insertions(+), 41 deletions(-) diff --git a/config.def.h b/config.def.h index b8536bb..aa71dd6 100644 --- a/config.def.h +++ b/config.def.h @@ -4,7 +4,7 @@ static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ static const unsigned int alpha = 0xe3; /* Amount of opacity. 0xff is opaque */ static int centered = 1; /* -c option; centers dmenu on screen */ -static int min_width = 1000; /* minimum width when centered */ +static int min_width = 1020; /* minimum width when centered */ /* -fn option overrides fonts[0]; default X11 font or font set */ static const char *fonts[] = { @@ -23,7 +23,7 @@ static const char *colors[SchemeLast][2] = { /* -l and -g options; controls number of lines and columns in grid if > 0 */ static unsigned int lines = 9; -static unsigned int columns = 2; +static unsigned int columns = 1; static const unsigned int alphas[SchemeLast][2] = { [SchemeNorm] = { OPAQUE, alpha }, diff --git a/dmenuc.py b/dmenuc.py index 72a2745..c6ee7c5 100755 --- a/dmenuc.py +++ b/dmenuc.py @@ -8,8 +8,22 @@ import stat from dataclasses import dataclass from typing import List, Union +def find_line_column(code, pos): + last_newline = code.rfind('\n', 0, pos) + line = code.count('\n', 0, pos) + if last_newline == -1: + column = pos + else: + column = pos - last_newline - 1 + return (line, column) + +def stringify_code_pos(code, pos): + line, column = find_line_column(code, pos) + return f"{line+1}:{column+1}" + TOKEN_SPECIFICATION = [ ('IMPORT', r'import'), + ('OPTIONS', r'options'), ('EVAL', r'eval'), ('OPTION', r'option'), ('DMENU', r'dmenu'), @@ -22,7 +36,6 @@ TOKEN_SPECIFICATION = [ TOKEN_REGEX = '|'.join(f'(?P<{name}>{pattern})' for name, pattern in TOKEN_SPECIFICATION) - @dataclass class Token: type: str @@ -33,7 +46,7 @@ class Token: return f'Token({self.type}, {self.value}, pos={self.pos})' -def tokenize(code): +def tokenize(code, filename): tokens = [] for mo in re.finditer(TOKEN_REGEX, code): kind = mo.lastgroup @@ -42,7 +55,7 @@ def tokenize(code): if kind == 'SKIP': continue elif kind == 'MISMATCH': - raise RuntimeError(f'Unexpected token {value!r} at position {pos}') + raise RuntimeError(f'Unexpected token {value!r} at position {stringify_code_pos(code, pos)}. File {filename}') else: tokens.append(Token(kind, value, pos)) return tokens @@ -80,10 +93,20 @@ class ActionDmenu: return f"dmenu {self.prompt} ( {' ; '.join(map(str, self.options))} )" +def resolve_path_relative_to_file(path_a, path_b): + if os.path.isabs(path_b): + return path_b + a_dir = os.path.dirname(os.path.abspath(path_a)) + path_c = os.path.normpath(os.path.join(a_dir, path_b)) + return path_c + + class Parser: - def __init__(self, tokens): + def __init__(self, tokens, filename, code): self.tokens = tokens self.pos = 0 + self.filename = filename + self.code = code def current(self): if self.pos < len(self.tokens): @@ -97,29 +120,46 @@ class Parser: if token.type == token_type: self.pos += 1 return token - raise RuntimeError(f"Expected token {token_type} at position {token.pos} but got {token.type}") + raise RuntimeError(f"Expected token {token_type} at position {stringify_code_pos(self.code, self.pos)} but got {token.type}. File {self.filename}") - # Grammar production: