├── .builds ├── alpine-x64.yml ├── alpine-x86.yml.disabled └── freebsd-x64.yml ├── .editorconfig ├── .forgejo └── issue_template │ ├── config.yml │ ├── issue_template.yaml │ └── issue_template.yml ├── .gitignore ├── .gitmodules ├── .woodpecker.yaml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── INSTALL.md ├── LICENSE ├── README.md ├── async.c ├── async.h ├── base64.c ├── base64.h ├── box-drawing.c ├── box-drawing.h ├── char32.c ├── char32.h ├── client-protocol.h ├── client.c ├── commands.c ├── commands.h ├── completions ├── bash │ ├── foot │ └── footclient ├── fish │ ├── foot.fish │ └── footclient.fish ├── meson.build └── zsh │ ├── _foot │ └── _footclient ├── composed.c ├── composed.h ├── config.c ├── config.h ├── csi.c ├── csi.h ├── cursor-shape.c ├── cursor-shape.h ├── dcs.c ├── dcs.h ├── debug.c ├── debug.h ├── doc ├── benchmark.md ├── foot-ctlseqs.7.scd ├── foot.1.scd ├── foot.ini.5.scd ├── footclient.1.scd ├── meson.build └── sixel-wow.png ├── extract.c ├── extract.h ├── fdm.c ├── fdm.h ├── foot-features.h ├── foot-server.desktop ├── foot-server.service.in ├── foot-server.socket ├── foot.desktop ├── foot.info ├── foot.ini ├── footclient.desktop ├── generate-version.sh ├── grid.c ├── grid.h ├── hsl.c ├── hsl.h ├── icons ├── hicolor │ ├── 48x48 │ │ └── apps │ │ │ └── foot.png │ └── scalable │ │ └── apps │ │ └── foot.svg └── meson.build ├── ime.c ├── ime.h ├── input.c ├── input.h ├── key-binding.c ├── key-binding.h ├── keymap.h ├── kitty-keymap.h ├── log.c ├── log.h ├── macros.h ├── main.c ├── meson.build ├── meson_options.txt ├── misc.c ├── misc.h ├── notify.c ├── notify.h ├── org.codeberg.dnkl.foot.metainfo.xml ├── osc.c ├── osc.h ├── pgo ├── full-current-session.sh ├── full-headless-cage.sh ├── full-headless-sway-inner.sh ├── full-headless-sway.sh ├── full-inner.sh ├── options ├── partial.sh ├── pgo.c └── pgo.sh ├── quirks.c ├── quirks.h ├── reaper.c ├── reaper.h ├── render.c ├── render.h ├── scripts ├── benchmark.py ├── generate-alt-random-writes.py ├── generate-builtin-terminfo.py └── generate-emoji-variation-sequences.py ├── search.c ├── search.h ├── selection.c ├── selection.h ├── server.c ├── server.h ├── shm-formats.h ├── shm.c ├── shm.h ├── sixel.c ├── sixel.h ├── slave.c ├── slave.h ├── spawn.c ├── spawn.h ├── stride.h ├── subprojects ├── fcft.wrap ├── tllist.wrap └── wayland-protocols.wrap ├── terminal.c ├── terminal.h ├── tests ├── meson.build └── test-config.c ├── themes ├── aeroroot ├── apprentice ├── ayu-mirage ├── catppuccin-frappe ├── catppuccin-latte ├── catppuccin-macchiato ├── catppuccin-mocha ├── chiba-dark ├── derp ├── deus ├── dracula ├── dracula-iterm ├── electrophoretic ├── gruvbox-dark ├── gruvbox-light ├── hacktober ├── jetbrains-darcula ├── kitty ├── material-amber ├── material-design ├── modus-operandi ├── modus-vivendi ├── monokai-pro ├── moonfly ├── neon ├── nightfly ├── noirblaze ├── nord ├── nordiq ├── nvim-dark ├── nvim-light ├── onedark ├── onehalf-dark ├── panda ├── paper-color-dark ├── paper-color-light ├── poimandres ├── rezza ├── rose-pine ├── selenized-black ├── selenized-dark ├── selenized-light ├── selenized-white ├── solarized-dark ├── solarized-dark-normal-brights ├── solarized-light ├── srcery ├── starlight ├── tango ├── tempus-autumn ├── tempus-classic ├── tempus-dawn ├── tempus-day ├── tempus-dusk ├── tempus-fugit ├── tempus-future ├── tempus-night ├── tempus-past ├── tempus-rift ├── tempus-spring ├── tempus-summer ├── tempus-tempest ├── tempus-totus ├── tempus-warp ├── tempus-winter ├── tokyonight-day ├── tokyonight-night ├── tokyonight-storm ├── visibone ├── xterm └── zenburn ├── tokenize.c ├── tokenize.h ├── unicode-mode.c ├── unicode-mode.h ├── unicode └── emoji-variation-sequences.txt ├── uri.c ├── uri.h ├── url-mode.c ├── url-mode.h ├── user-notification.c ├── user-notification.h ├── util.h ├── utils ├── meson.build └── xtgettcap.c ├── vt.c ├── vt.h ├── wayland.c ├── wayland.h ├── xmalloc.c ├── xmalloc.h ├── xsnprintf.c └── xsnprintf.h /.builds/alpine-x64.yml: -------------------------------------------------------------------------------- 1 | image: alpine/edge 2 | packages: 3 | - musl-dev 4 | - eudev-libs 5 | - eudev-dev 6 | - linux-headers 7 | - meson 8 | - ninja 9 | - gcc 10 | - scdoc 11 | - wayland-dev 12 | - wayland-protocols 13 | - freetype-dev 14 | - fontconfig-dev 15 | - harfbuzz-dev 16 | - utf8proc-dev 17 | - pixman-dev 18 | - libxkbcommon-dev 19 | - ncurses 20 | - python3 21 | - py3-pip 22 | - check-dev 23 | - ttf-hack 24 | - font-noto-emoji 25 | 26 | sources: 27 | - https://git.sr.ht/~dnkl/foot 28 | 29 | # triggers: 30 | # - action: email 31 | # condition: failure 32 | # to: 33 | 34 | tasks: 35 | - fcft: | 36 | cd foot/subprojects 37 | git clone https://codeberg.org/dnkl/fcft.git 38 | cd ../.. 39 | - debug: | 40 | mkdir -p bld/debug 41 | meson --buildtype=debug -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/debug 42 | ninja -C bld/debug -k0 43 | meson test -C bld/debug --print-errorlogs 44 | - release: | 45 | mkdir -p bld/release 46 | meson --buildtype=minsize -Db_pgo=generate -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/release 47 | ninja -C bld/release -k0 48 | meson test -C bld/release --print-errorlogs 49 | - codespell: | 50 | python3 -m venv codespell-venv 51 | source codespell-venv/bin/activate 52 | pip install codespell 53 | cd foot 54 | ~/.local/bin/codespell -Lser,doas,zar README.md INSTALL.md CHANGELOG.md *.c *.h doc/*.scd 55 | deactivate 56 | -------------------------------------------------------------------------------- /.builds/alpine-x86.yml.disabled: -------------------------------------------------------------------------------- 1 | image: alpine/edge 2 | arch: x86 3 | packages: 4 | - musl-dev 5 | - eudev-libs 6 | - eudev-dev 7 | - linux-headers 8 | - meson 9 | - ninja 10 | - gcc 11 | - scdoc 12 | - wayland-dev 13 | - wayland-protocols 14 | - freetype-dev 15 | - fontconfig-dev 16 | - harfbuzz-dev 17 | - utf8proc-dev 18 | - pixman-dev 19 | - libxkbcommon-dev 20 | - ncurses 21 | - check-dev 22 | - ttf-hack 23 | - font-noto-emoji 24 | 25 | sources: 26 | - https://git.sr.ht/~dnkl/foot 27 | 28 | # triggers: 29 | # - action: email 30 | # condition: failure 31 | # to: 32 | 33 | tasks: 34 | - debug: | 35 | mkdir -p bld/debug 36 | meson --buildtype=debug -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/debug 37 | ninja -C bld/debug -k0 38 | meson test -C bld/debug --print-errorlogs 39 | - release: | 40 | mkdir -p bld/release 41 | meson --buildtype=minsize -Db_pgo=generate -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/release 42 | ninja -C bld/release -k0 43 | meson test -C bld/release --print-errorlogs 44 | -------------------------------------------------------------------------------- /.builds/freebsd-x64.yml: -------------------------------------------------------------------------------- 1 | image: freebsd/latest 2 | packages: 3 | - evdev-proto 4 | - libepoll-shim 5 | - meson 6 | - ninja 7 | - pkgconf 8 | - scdoc 9 | - wayland 10 | - wayland-protocols 11 | - freetype2 12 | - fontconfig 13 | - harfbuzz 14 | - utf8proc 15 | - pixman 16 | - libxkbcommon 17 | - check 18 | - hack-font 19 | - noto-emoji 20 | 21 | sources: 22 | - https://git.sr.ht/~dnkl/foot 23 | 24 | # triggers: 25 | # - action: email 26 | # condition: failure 27 | # to: 28 | 29 | tasks: 30 | - fcft: | 31 | cd foot/subprojects 32 | git clone https://codeberg.org/dnkl/fcft.git 33 | cd ../.. 34 | - debug: | 35 | mkdir -p bld/debug 36 | meson --buildtype=debug -Dterminfo=disabled -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/debug 37 | ninja -C bld/debug -k0 38 | meson test -C bld/debug --print-errorlogs 39 | bld/debug/foot --version 40 | bld/debug/footclient --version 41 | 42 | - release: | 43 | mkdir -p bld/release 44 | meson --buildtype=minsize -Db_pgo=generate -Dterminfo=disabled -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true foot bld/release 45 | ninja -C bld/release -k0 46 | meson test -C bld/release --print-errorlogs 47 | bld/release/foot --version 48 | bld/release/footclient --version 49 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | charset = utf-8 8 | indent_style = space 9 | indent_size = 4 10 | max_line_length = 70 11 | 12 | [{meson.build,PKGBUILD}] 13 | indent_size = 2 14 | 15 | [*.scd] 16 | indent_style = tab 17 | trim_trailing_whitespace = false 18 | -------------------------------------------------------------------------------- /.forgejo/issue_template/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: IRC 4 | url: https://web.libera.chat/?channels=#foot 5 | about: Join the IRC channel for foot-related discussion and support 6 | -------------------------------------------------------------------------------- /.forgejo/issue_template/issue_template.yaml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Request a new feature 3 | labels: ["enhancement"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Please search the man page (`foot.ini(5)` and `foot(1)`); 9 | maybe the feature already exists? 10 | 11 | If the feature does not exist in your installed version of 12 | foot, please check the **latest** version of foot; maybe the 13 | feature has already been added? 14 | 15 | Please describe your feature request in as much details as 16 | possible. Describe your use case. Explain why the existing 17 | feature set is not sufficient. Foot is (trying to be) a 18 | minimalistic terminal emulator; explain how your desired 19 | feature does not add bloat. 20 | - type: textarea 21 | id: request 22 | attributes: 23 | label: Describe your feature request 24 | validations: 25 | required: true 26 | 27 | -------------------------------------------------------------------------------- /.forgejo/issue_template/issue_template.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | labels: ["bug"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Please provide as many details as possible, we must be able to 9 | understand the bug in order to fix it. 10 | 11 | Don't forget to search the issue tracker in case there is 12 | already an open issue for the bug you found. 13 | - type: input 14 | id: version 15 | attributes: 16 | label: Foot Version 17 | description: "The output of `foot --version`" 18 | placeholder: "foot version: 1.17.2-11-gc4f13809 (May 20 2024, branch 'master') +pgo +ime +graphemes -assertions" 19 | validations: 20 | required: true 21 | - type: input 22 | id: term 23 | attributes: 24 | label: TERM environment variable 25 | description: "The output of `echo $TERM`" 26 | placeholder: "foot" 27 | validations: 28 | required: true 29 | - type: input 30 | id: compositor 31 | attributes: 32 | label: Compositor Version 33 | description: "The name and version of your compositor" 34 | placeholder: "sway version 1.9" 35 | validations: 36 | required: true 37 | - type: textarea 38 | id: repro 39 | attributes: 40 | label: Description of Bug and Steps to Reproduce 41 | description: | 42 | Exactly what steps can someone else take to see the bug 43 | themselves? What happens? 44 | validations: 45 | required: true 46 | - type: markdown 47 | attributes: 48 | value: | 49 | Please provide as many details as possible, we must be able to 50 | understand the bug in order to fix it. 51 | 52 | Other software 53 | -------------- 54 | 55 | **Compositors**: have you tested other compositors? Does the 56 | issue happen on all of them, or only your main compositor? 57 | 58 | **Terminal multiplexers**: are you using tmux, zellij, or any 59 | other terminal multiplexer? Does the bug happen in a plain 60 | foot instance? 61 | 62 | **IME** do you use an IME? Which one? Does the bug happen if 63 | you disable the IME? 64 | 65 | Obtaining logs and stacktraces 66 | ------------------------------ 67 | 68 | Use a [debug 69 | build](https://codeberg.org/dnkl/foot/src/branch/master/INSTALL.md#debug-build) 70 | of foot if possible, to get a better quality stacktrace in 71 | case of a crash. 72 | 73 | Run foot with logging enabled: 74 | ```sh 75 | foot -d info 2> foot.log 76 | ``` 77 | 78 | In many cases, tracing the Wayland communication is extremely helpful: 79 | ```sh 80 | WAYLAND_DEBUG=1 foot -d info 2> foot.wayland.log 81 | ``` 82 | 83 | Reproduce your problem as quickly as possible, and then exit foot. 84 | - type: textarea 85 | id: logs 86 | attributes: 87 | label: Relevant logs, stacktraces, etc. 88 | - type: markdown 89 | attributes: 90 | value: | 91 | Please attach files instead of pasting the logs, if the logs are large 92 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bld/ 2 | /pkg/ 3 | /src/ 4 | /subprojects/*/ 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanteAlighierin/foot/a42fec49280b2d8775dcfe4c879f6fcd8dd4d8e5/.gitmodules -------------------------------------------------------------------------------- /.woodpecker.yaml: -------------------------------------------------------------------------------- 1 | # -*- yaml -*- 2 | 3 | steps: 4 | - name: codespell 5 | when: 6 | - event: [manual, pull_request] 7 | - event: [push, tag] 8 | branch: [master, releases/*] 9 | image: alpine:edge 10 | commands: 11 | - apk add openssl 12 | - apk add python3 13 | - apk add py3-pip 14 | - python3 -m venv codespell-venv 15 | - source codespell-venv/bin/activate 16 | - pip install codespell 17 | - codespell -Lser,doas,zar README.md INSTALL.md CHANGELOG.md *.c *.h doc/*.scd 18 | - deactivate 19 | 20 | - name: subprojects 21 | when: 22 | - event: [manual, pull_request] 23 | - event: [push, tag] 24 | branch: [master, releases/*] 25 | image: alpine:edge 26 | commands: 27 | - apk add git 28 | - mkdir -p subprojects && cd subprojects 29 | - git clone https://codeberg.org/dnkl/tllist.git 30 | - git clone https://codeberg.org/dnkl/fcft.git 31 | - cd .. 32 | 33 | - name: x64 34 | when: 35 | - event: [manual, pull_request] 36 | - event: [push, tag] 37 | branch: [master, releases/*] 38 | depends_on: [subprojects] 39 | image: alpine:edge 40 | commands: 41 | - apk update 42 | - apk add musl-dev linux-headers meson ninja gcc clang scdoc ncurses 43 | - apk add libxkbcommon-dev pixman-dev freetype-dev fontconfig-dev harfbuzz-dev utf8proc-dev 44 | - apk add wayland-dev wayland-protocols 45 | - apk add git 46 | - apk add check-dev 47 | - apk add ttf-hack font-noto-emoji 48 | 49 | # Debug 50 | - mkdir -p bld/debug-x64 51 | - cd bld/debug-x64 52 | - meson --buildtype=debug -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../.. 53 | - ninja -v -k0 54 | - ninja -v test 55 | - ./foot --version 56 | - ./footclient --version 57 | - cd ../.. 58 | 59 | # Release (gcc) 60 | - mkdir -p bld/release-x64 61 | - cd bld/release-x64 62 | - meson --buildtype=release -Db_pgo=generate -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../.. 63 | - ninja -v -k0 64 | - ninja -v test 65 | - ./foot --version 66 | - ./footclient --version 67 | - cd ../.. 68 | 69 | # Release (clang) 70 | - mkdir -p bld/release-x64-clang 71 | - cd bld/release-x64-clang 72 | - CC=clang meson --buildtype=release -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../.. 73 | - ninja -v -k0 74 | - ninja -v test 75 | - ./foot --version 76 | - ./footclient --version 77 | - cd ../.. 78 | 79 | # no grapheme clustering 80 | - apk del harfbuzz harfbuzz-dev utf8proc utf8proc-dev 81 | - mkdir -p bld/debug 82 | - cd bld/debug 83 | - meson --buildtype=debug -Dgrapheme-clustering=disabled -Dfcft:grapheme-shaping=disabled -Dfcft:run-shaping=disabled -Dfcft:test-text-shaping=false ../.. 84 | - ninja -v -k0 85 | - ninja -v test 86 | - ./foot --version 87 | - ./footclient --version 88 | - cd ../.. 89 | 90 | - name: x86 91 | when: 92 | - event: [manual, pull_request] 93 | - event: [push, tag] 94 | branch: [master, releases/*] 95 | depends_on: [subprojects] 96 | image: i386/alpine:edge 97 | commands: 98 | - apk update 99 | - apk add musl-dev linux-headers meson ninja gcc clang scdoc ncurses 100 | - apk add libxkbcommon-dev pixman-dev freetype-dev fontconfig-dev harfbuzz-dev utf8proc-dev 101 | - apk add wayland-dev wayland-protocols 102 | - apk add git 103 | - apk add check-dev 104 | - apk add ttf-hack font-noto-emoji 105 | 106 | # Debug 107 | - mkdir -p bld/debug-x86 108 | - cd bld/debug-x86 109 | - meson --buildtype=debug -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../.. 110 | - ninja -v -k0 111 | - ninja -v test 112 | - ./foot --version 113 | - ./footclient --version 114 | - cd ../.. 115 | 116 | # Release (gcc) 117 | - mkdir -p bld/release-x86 118 | - cd bld/release-x86 119 | - meson --buildtype=release -Db_pgo=generate -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../.. 120 | - ninja -v -k0 121 | - ninja -v test 122 | - ./foot --version 123 | - ./footclient --version 124 | - cd ../.. 125 | 126 | # Release (clang) 127 | - mkdir -p bld/release-x86-clang 128 | - cd bld/release-x86-clang 129 | - CC=clang meson --buildtype=release -Dgrapheme-clustering=enabled -Dfcft:grapheme-shaping=enabled -Dfcft:run-shaping=enabled -Dfcft:test-text-shaping=true ../.. 130 | - ninja -v -k0 131 | - ninja -v test 132 | - ./foot --version 133 | - ./footclient --version 134 | - cd ../.. 135 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Foot Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | Participants in the foot community are expected to uphold the described 54 | standards not only in official community spaces (issue trackers, IRC channels, 55 | etc.) but in all public spaces. The Code of Conduct however does acknowledge 56 | that people are fallible and that it is possible to truely correct a past 57 | pattern of unacceptable behavior. That is to say, the scope of the Code of 58 | Conduct does not necessarily extend into the distant past. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior 63 | may be reported to the community leaders responsible for enforcement 64 | at [daniel@ekloef.se](mailto:daniel@ekloef.se). All complaints will 65 | be reviewed and investigated promptly and fairly. 66 | 67 | All community leaders are obligated to respect the privacy and security of the 68 | reporter of any incident. 69 | 70 | The consequences for Code of Conduct violations will be decided upon and 71 | enforced by community leaders. These may include a formal warning, a temporary 72 | ban from community spaces, a permanent ban from community spaces, etc. 73 | 74 | There are no hard and fast rules for exactly what behavior in which space will 75 | result in what consequences, it is up to the community leaders to enforce the 76 | Code of Conduct in a way that they believe best promotes a healthy community. 77 | 78 | ## Attribution 79 | 80 | This Code of Conduct is adapted from the 81 | [Contributor Covenant](https://www.contributor-covenant.org/), 82 | version 2.1, available at 83 | https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. 84 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Daniel Eklöf 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /async.c: -------------------------------------------------------------------------------- 1 | #include "async.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define LOG_MODULE "async" 8 | #define LOG_ENABLE_DBG 0 9 | #include "log.h" 10 | 11 | enum async_write_status 12 | async_write(int fd, const void *_data, size_t len, size_t *idx) 13 | { 14 | const uint8_t *const data = _data; 15 | size_t left = len - *idx; 16 | 17 | while (left > 0) { 18 | ssize_t ret = write(fd, &data[*idx], left); 19 | 20 | if (ret < 0) { 21 | if (errno == EAGAIN || errno == EWOULDBLOCK) 22 | return ASYNC_WRITE_REMAIN; 23 | 24 | return ASYNC_WRITE_ERR; 25 | } 26 | 27 | LOG_DBG("wrote %zd bytes of %zu (%zu left) to FD=%d", 28 | ret, left, left - ret, fd); 29 | 30 | *idx += ret; 31 | left -= ret; 32 | } 33 | 34 | return ASYNC_WRITE_DONE; 35 | } 36 | -------------------------------------------------------------------------------- /async.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | enum async_write_status {ASYNC_WRITE_DONE, ASYNC_WRITE_REMAIN, ASYNC_WRITE_ERR}; 6 | 7 | /* 8 | * Primitive that writes data to a NONBLOCK:ing FD. 9 | * 10 | * _data: points to the beginning of the buffer 11 | * len: total size of the data buffer 12 | * idx: pointer to byte offset into data buffer - writing starts here. 13 | * 14 | * Thus, the total amount of data to write is (len - *idx). *idx is 15 | * updated such that it points to the next unwritten byte in the data 16 | * buffer. 17 | * 18 | * I.e. if the return value is: 19 | * - ASYNC_WRITE_DONE, then the *idx == len. 20 | * - ASYNC_WRITE_REMAIN, then *idx < len 21 | * - ASYNC_WRITE_ERR, there was an error, and no data was written 22 | */ 23 | enum async_write_status async_write( 24 | int fd, const void *data, size_t len, size_t *idx); 25 | -------------------------------------------------------------------------------- /base64.c: -------------------------------------------------------------------------------- 1 | #include "base64.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define LOG_MODULE "base64" 10 | #define LOG_ENABLE_DBG 0 11 | #include "log.h" 12 | #include "debug.h" 13 | 14 | enum { 15 | P = 1 << 6, // Padding byte (=) 16 | I = 1 << 7, // Invalid byte ([^A-Za-z0-9+/=]) 17 | }; 18 | 19 | static const uint8_t reverse_lookup[256] = { 20 | I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, 21 | I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, 22 | I, I, I, I, I, I, I, I, I, I, I, 62, I, I, I, 63, 23 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, I, I, I, P, I, I, 24 | I, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 25 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, I, I, I, I, I, 26 | I, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 27 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, I, I, I, I, I, 28 | I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, 29 | I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, 30 | I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, 31 | I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, 32 | I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, 33 | I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, 34 | I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, 35 | I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I 36 | }; 37 | 38 | static const char lookup[64] = { 39 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 40 | "abcdefghijklmnopqrstuvwxyz" 41 | "0123456789+/" 42 | }; 43 | 44 | char * 45 | base64_decode(const char *s, size_t *size) 46 | { 47 | const size_t len = strlen(s); 48 | if (unlikely(len % 4 != 0)) { 49 | errno = EINVAL; 50 | return NULL; 51 | } 52 | 53 | char *ret = malloc(len / 4 * 3 + 1); 54 | if (unlikely(ret == NULL)) 55 | return NULL; 56 | 57 | if (unlikely(size != NULL)) 58 | *size = len / 4 * 3; 59 | 60 | for (size_t i = 0, o = 0; i < len; i += 4, o += 3) { 61 | unsigned a = reverse_lookup[(unsigned char)s[i + 0]]; 62 | unsigned b = reverse_lookup[(unsigned char)s[i + 1]]; 63 | unsigned c = reverse_lookup[(unsigned char)s[i + 2]]; 64 | unsigned d = reverse_lookup[(unsigned char)s[i + 3]]; 65 | 66 | unsigned u = a | b | c | d; 67 | if (unlikely(u & I)) 68 | goto invalid; 69 | 70 | if (unlikely(u & P)) { 71 | if (unlikely(i + 4 != len || (a | b) & P || (c & P && !(d & P)))) 72 | goto invalid; 73 | 74 | if (unlikely(size != NULL)) { 75 | if (c & P) 76 | *size = len / 4 * 3 - 2; 77 | else 78 | *size = len / 4 * 3 - 1; 79 | } 80 | 81 | c &= 63; 82 | d &= 63; 83 | } 84 | 85 | uint32_t v = a << 18 | b << 12 | c << 6 | d << 0; 86 | char x = (v >> 16) & 0xff; 87 | char y = (v >> 8) & 0xff; 88 | char z = (v >> 0) & 0xff; 89 | 90 | LOG_DBG("%c%c%c", x, y, z); 91 | ret[o + 0] = x; 92 | ret[o + 1] = y; 93 | ret[o + 2] = z; 94 | } 95 | 96 | ret[len / 4 * 3] = '\0'; 97 | return ret; 98 | 99 | invalid: 100 | free(ret); 101 | errno = EINVAL; 102 | return NULL; 103 | } 104 | 105 | char * 106 | base64_encode(const uint8_t *data, size_t size) 107 | { 108 | xassert(size % 3 == 0); 109 | if (unlikely(size % 3 != 0)) 110 | return NULL; 111 | 112 | char *ret = malloc(size / 3 * 4 + 1); 113 | if (unlikely(ret == NULL)) 114 | return NULL; 115 | 116 | for (size_t i = 0, o = 0; i < size; i += 3, o += 4) { 117 | int x = data[i + 0]; 118 | int y = data[i + 1]; 119 | int z = data[i + 2]; 120 | 121 | uint32_t v = x << 16 | y << 8 | z << 0; 122 | 123 | unsigned a = (v >> 18) & 0x3f; 124 | unsigned b = (v >> 12) & 0x3f; 125 | unsigned c = (v >> 6) & 0x3f; 126 | unsigned d = (v >> 0) & 0x3f; 127 | 128 | char c0 = lookup[a]; 129 | char c1 = lookup[b]; 130 | char c2 = lookup[c]; 131 | char c3 = lookup[d]; 132 | 133 | ret[o + 0] = c0; 134 | ret[o + 1] = c1; 135 | ret[o + 2] = c2; 136 | ret[o + 3] = c3; 137 | 138 | LOG_DBG("base64: encode: %c%c%c%c", c0, c1, c2, c3); 139 | } 140 | 141 | ret[size / 3 * 4] = '\0'; 142 | return ret; 143 | } 144 | 145 | void 146 | base64_encode_final(const uint8_t *data, size_t size, char result[4]) 147 | { 148 | xassert(size > 0); 149 | xassert(size < 3); 150 | 151 | uint32_t v = 0; 152 | if (size >= 1) 153 | v |= data[0] << 16; 154 | if (size >= 2) 155 | v |= data[1] << 8; 156 | 157 | unsigned a = (v >> 18) & 0x3f; 158 | unsigned b = (v >> 12) & 0x3f; 159 | unsigned c = (v >> 6) & 0x3f; 160 | 161 | char c0 = lookup[a]; 162 | char c1 = lookup[b]; 163 | char c2 = size == 2 ? lookup[c] : '='; 164 | char c3 = '='; 165 | 166 | result[0] = c0; 167 | result[1] = c1; 168 | result[2] = c2; 169 | result[3] = c3; 170 | 171 | LOG_DBG("base64: encode: %c%c%c%c", c0, c1, c2, c3); 172 | } 173 | -------------------------------------------------------------------------------- /base64.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | char *base64_decode(const char *s, size_t *out_len); 7 | char *base64_encode(const uint8_t *data, size_t size); 8 | void base64_encode_final(const uint8_t *data, size_t size, char result[4]); 9 | -------------------------------------------------------------------------------- /box-drawing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | struct terminal; 7 | struct fcft_glyph *box_drawing(const struct terminal *term, char32_t wc); 8 | -------------------------------------------------------------------------------- /char32.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static inline size_t c32len(const char32_t *s) { 12 | return wcslen((const wchar_t *)s); 13 | } 14 | 15 | static inline int c32cmp(const char32_t *s1, const char32_t *s2) { 16 | return wcscmp((const wchar_t *)s1, (const wchar_t *)s2); 17 | } 18 | 19 | static inline char32_t *c32ncpy(char32_t *dst, const char32_t *src, size_t n) { 20 | return (char32_t *)wcsncpy((wchar_t *)dst, (const wchar_t *)src, n); 21 | } 22 | 23 | static inline char32_t *c32cpy(char32_t *dst, const char32_t *src) { 24 | return (char32_t *)wcscpy((wchar_t *)dst, (const wchar_t *)src); 25 | } 26 | 27 | static inline char32_t *c32ncat(char32_t *dst, const char32_t *src, size_t n) { 28 | return (char32_t *)wcsncat((wchar_t *)dst, (const wchar_t *)src, n); 29 | } 30 | 31 | static inline char32_t *c32cat(char32_t *dst, const char32_t *src) { 32 | return (char32_t *)wcscat((wchar_t *)dst, (const wchar_t *)src); 33 | } 34 | 35 | static inline char32_t *c32dup(const char32_t *s) { 36 | return (char32_t *)wcsdup((const wchar_t *)s); 37 | } 38 | 39 | static inline char32_t *c32chr(const char32_t *s, char32_t c) { 40 | return (char32_t *)wcschr((const wchar_t *)s, c); 41 | } 42 | 43 | static inline int c32casecmp(const char32_t *s1, const char32_t *s2) { 44 | return wcscasecmp((const wchar_t *)s1, (const wchar_t *)s2); 45 | } 46 | 47 | static inline int c32ncasecmp(const char32_t *s1, const char32_t *s2, size_t n) { 48 | return wcsncasecmp((const wchar_t *)s1, (const wchar_t *)s2, n); 49 | } 50 | 51 | static inline char32_t toc32lower(char32_t c) { 52 | return (char32_t)towlower((wint_t)c); 53 | } 54 | 55 | static inline char32_t toc32upper(char32_t c) { 56 | return (char32_t)towupper((wint_t)c); 57 | } 58 | 59 | static inline bool isc32space(char32_t c32) { 60 | return iswspace((wint_t)c32); 61 | } 62 | 63 | static inline bool isc32print(char32_t c32) { 64 | return iswprint((wint_t)c32); 65 | } 66 | 67 | static inline bool isc32graph(char32_t c32) { 68 | return iswgraph((wint_t)c32); 69 | } 70 | 71 | static inline int c32width(char32_t c) { 72 | return wcwidth((wchar_t)c); 73 | } 74 | 75 | static inline int c32swidth(const char32_t *s, size_t n) { 76 | return wcswidth((const wchar_t *)s, n); 77 | } 78 | 79 | size_t mbsntoc32(char32_t *dst, const char *src, size_t nms, size_t len); 80 | char32_t *ambstoc32(const char *src); 81 | char *ac32tombs(const char32_t *src); 82 | 83 | static inline size_t mbstoc32(char32_t *dst, const char *src, size_t len) { 84 | return mbsntoc32(dst, src, strlen(src) + 1, len); 85 | } 86 | -------------------------------------------------------------------------------- /client-protocol.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | struct client_string { 8 | uint16_t len; 9 | /* char str[static len]; */ 10 | }; 11 | 12 | struct client_data { 13 | bool hold:1; 14 | bool no_wait:1; 15 | bool xdga_token:1; 16 | uint8_t reserved:5; 17 | 18 | uint8_t token_len; 19 | uint16_t cwd_len; 20 | uint16_t override_count; 21 | uint16_t argc; 22 | uint16_t env_count; 23 | 24 | /* char cwd[static cwd_len]; */ 25 | /* char token[static token_len]; */ 26 | /* struct client_string overrides[static override_count]; */ 27 | /* struct client_string argv[static argc]; */ 28 | /* struct client_string envp[static env_count]; */ 29 | } __attribute__((packed)); 30 | 31 | _Static_assert(sizeof(struct client_data) == 10, "protocol struct size error"); 32 | -------------------------------------------------------------------------------- /commands.c: -------------------------------------------------------------------------------- 1 | #include "commands.h" 2 | 3 | #define LOG_MODULE "commands" 4 | #define LOG_ENABLE_DBG 0 5 | #include "log.h" 6 | #include "grid.h" 7 | #include "render.h" 8 | #include "selection.h" 9 | #include "terminal.h" 10 | #include "url-mode.h" 11 | #include "util.h" 12 | 13 | void 14 | cmd_scrollback_up(struct terminal *term, int rows) 15 | { 16 | if (term->grid == &term->alt) 17 | return; 18 | if (urls_mode_is_active(term)) 19 | return; 20 | 21 | const struct grid *grid = term->grid; 22 | const int view = grid->view; 23 | const int grid_rows = grid->num_rows; 24 | 25 | /* The view row number in scrollback relative coordinates. This is 26 | * the maximum number of rows we're allowed to scroll */ 27 | int sb_start = grid_sb_start_ignore_uninitialized(grid, term->rows); 28 | int view_sb_rel = 29 | grid_row_abs_to_sb_precalc_sb_start(grid, sb_start, view); 30 | 31 | rows = min(rows, view_sb_rel); 32 | if (rows == 0) 33 | return; 34 | 35 | int new_view = (view + grid_rows) - rows; 36 | new_view &= grid_rows - 1; 37 | 38 | xassert(new_view != view); 39 | xassert(grid->rows[new_view] != NULL); 40 | #if defined(_DEBUG) 41 | for (int r = 0; r < term->rows; r++) 42 | xassert(grid->rows[(new_view + r) & (grid->num_rows - 1)] != NULL); 43 | #endif 44 | 45 | LOG_DBG("scrollback UP: %d -> %d (offset = %d, rows = %d)", 46 | view, new_view, offset, grid_rows); 47 | 48 | selection_view_up(term, new_view); 49 | term->grid->view = new_view; 50 | 51 | if (rows < term->rows) { 52 | term_damage_scroll( 53 | term, DAMAGE_SCROLL_REVERSE_IN_VIEW, 54 | (struct scroll_region){0, term->rows}, rows); 55 | term_damage_rows_in_view(term, 0, rows - 1); 56 | } else 57 | term_damage_view(term); 58 | 59 | render_refresh_urls(term); 60 | render_refresh(term); 61 | } 62 | 63 | void 64 | cmd_scrollback_down(struct terminal *term, int rows) 65 | { 66 | if (term->grid == &term->alt) 67 | return; 68 | if (urls_mode_is_active(term)) 69 | return; 70 | 71 | const struct grid *grid = term->grid; 72 | const int offset = grid->offset; 73 | const int view = grid->view; 74 | const int grid_rows = grid->num_rows; 75 | const int screen_rows = term->rows; 76 | 77 | const int scrollback_end = offset; 78 | 79 | /* Number of rows to scroll, without going past the scrollback end */ 80 | int max_rows = 0; 81 | if (view <= scrollback_end) 82 | max_rows = scrollback_end - view; 83 | else 84 | max_rows = offset + (grid_rows - view); 85 | 86 | rows = min(rows, max_rows); 87 | if (rows == 0) 88 | return; 89 | 90 | int new_view = (view + rows) & (grid_rows - 1); 91 | 92 | xassert(new_view != view); 93 | xassert(grid->rows[new_view] != NULL); 94 | #if defined(_DEBUG) 95 | for (int r = 0; r < term->rows; r++) 96 | xassert(grid->rows[(new_view + r) & (grid_rows - 1)] != NULL); 97 | #endif 98 | 99 | LOG_DBG("scrollback DOWN: %d -> %d (offset = %d, rows = %d)", 100 | view, new_view, offset, grid_rows); 101 | 102 | selection_view_down(term, new_view); 103 | term->grid->view = new_view; 104 | 105 | if (rows < term->rows) { 106 | term_damage_scroll( 107 | term, DAMAGE_SCROLL_IN_VIEW, 108 | (struct scroll_region){0, term->rows}, rows); 109 | term_damage_rows_in_view(term, term->rows - rows, screen_rows - 1); 110 | } else 111 | term_damage_view(term); 112 | 113 | render_refresh_urls(term); 114 | render_refresh(term); 115 | } 116 | -------------------------------------------------------------------------------- /commands.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "terminal.h" 4 | 5 | void cmd_scrollback_up(struct terminal *term, int rows); 6 | void cmd_scrollback_down(struct terminal *term, int rows); 7 | -------------------------------------------------------------------------------- /completions/bash/foot: -------------------------------------------------------------------------------- 1 | # Bash completion script for foot 2 | _foot() 3 | { 4 | COMPREPLY=() 5 | 6 | local cur prev flags word commands match previous_words i offset 7 | flags=( 8 | "--app-id" 9 | "--check-config" 10 | "--config" 11 | "--font" 12 | "--fullscreen" 13 | "--help" 14 | "--hold" 15 | "--log-colorize" 16 | "--log-level" 17 | "--log-no-syslog" 18 | "--login-shell" 19 | "--maximized" 20 | "--override" 21 | "--print-pid" 22 | "--pty" 23 | "--server" 24 | "--term" 25 | "--title" 26 | "--version" 27 | "--window-size-pixels" 28 | "--window-size-chars" 29 | "--working-directory" 30 | ) 31 | flags="${flags[@]}" 32 | cur=${COMP_WORDS[COMP_CWORD]} 33 | prev=${COMP_WORDS[COMP_CWORD-1]} 34 | 35 | # Check if positional argument is completed 36 | previous_words=( "${COMP_WORDS[@]}" ) 37 | unset previous_words[-1] 38 | commands=$(compgen -c | grep -vFx "$(compgen -k)" | grep -vE '^([.:[]|foot)$' | sort -u) 39 | i=0 40 | for word in "${previous_words[@]}" ; do 41 | match=$(printf "$commands" | grep -Fx "$word" 2>/dev/null) 42 | if [[ ! -z "$match" ]] ; then 43 | if [[ ${COMP_WORDS[i-1]} =~ ^(--app-id|--config|--font|--log-level|--pty|--term|--title|--window-size-pixels|--window-size-chars|--working-directory)$ ]] ; then 44 | (( i++ )) 45 | continue 46 | fi 47 | # Positional argument found 48 | offset=$i 49 | fi 50 | (( i++ )) 51 | done 52 | 53 | if [[ ! -z "$offset" ]] ; then 54 | # Depends on bash_completion being available 55 | declare -F _command_offset >/dev/null || return 1 56 | _command_offset $offset 57 | return 0 58 | elif [[ ${cur} == --* ]] ; then 59 | COMPREPLY=( $(compgen -W "${flags}" -- ${cur}) ) 60 | return 0 61 | fi 62 | 63 | case "$prev" in 64 | --config|--print-pid|--server|-[cps]) 65 | compopt -o default ;; 66 | --working-directory|-D) 67 | compopt -o dirnames ;; 68 | --term|-t) 69 | command -v toe > /dev/null || return 1 70 | COMPREPLY=( $(compgen -W "$(toe -a | awk '$1 !~ /[+]/ {print $1}')" -- ${cur}) ) ;; 71 | --font|-f) 72 | command -v fc-list > /dev/null || return 1 73 | COMPREPLY=( $(compgen -W "$(fc-list : family | sed 's/,/\n/g' | uniq | tr -d ' ')" -- ${cur}) ) ;; 74 | --log-level|-d) 75 | COMPREPLY=( $(compgen -W "none error warning info" -- ${cur}) ) ;; 76 | --log-colorize|-l) 77 | COMPREPLY=( $(compgen -W "never always auto" -- ${cur}) ) ;; 78 | --app-id|--help|--override|--pty|--title|--version|--window-size-chars|--window-size-pixels|--check-config|-[ahoTvWwC]) 79 | # Don't autocomplete for these flags 80 | : ;; 81 | *) 82 | # Complete commands from $PATH 83 | COMPREPLY=( $(compgen -c -- ${cur}) ) ;; 84 | esac 85 | 86 | return 0 87 | } 88 | 89 | complete -F _foot foot 90 | -------------------------------------------------------------------------------- /completions/bash/footclient: -------------------------------------------------------------------------------- 1 | # Bash completion script for footclient 2 | _footclient() 3 | { 4 | COMPREPLY=() 5 | 6 | local cur prev flags word commands match previous_words i offset 7 | flags=( 8 | "--app-id" 9 | "--fullscreen" 10 | "--help" 11 | "--hold" 12 | "--login-shell" 13 | "--log-level" 14 | "--log-colorize" 15 | "--maximized" 16 | "--override" 17 | "--client-environment" 18 | "--server-socket" 19 | "--term" 20 | "--title" 21 | "--version" 22 | "--window-size-pixels" 23 | "--window-size-chars" 24 | "--working-directory" 25 | ) 26 | flags="${flags[@]}" 27 | cur=${COMP_WORDS[COMP_CWORD]} 28 | prev=${COMP_WORDS[COMP_CWORD-1]} 29 | 30 | # Check if positional argument is completed 31 | previous_words=( "${COMP_WORDS[@]}" ) 32 | unset previous_words[-1] 33 | commands=$(compgen -c | grep -vFx "$(compgen -k)" | grep -vE '^([.:[]|footclient)$' | sort -u) 34 | i=0 35 | for word in "${previous_words[@]}" ; do 36 | match=$(printf "$commands" | grep -Fx "$word" 2>/dev/null) 37 | if [[ ! -z "$match" ]] ; then 38 | if [[ ${COMP_WORDS[i-1]} =~ ^(--app-id|--log-level|--server-socket|--term|--title|--window-size-pixels|--window-size-chars|--working-directory)$ ]] ; then 39 | (( i++ )) 40 | continue 41 | fi 42 | # Positional argument found 43 | offset=$i 44 | fi 45 | (( i++ )) 46 | done 47 | 48 | if [[ ! -z "$offset" ]] ; then 49 | # Depends on bash_completion being available 50 | declare -F _command_offset >/dev/null || return 1 51 | _command_offset $offset 52 | return 0 53 | elif [[ ${cur} == --* ]] ; then 54 | COMPREPLY=( $(compgen -W "${flags}" -- ${cur}) ) 55 | return 0 56 | fi 57 | 58 | case "$prev" in 59 | --server-socket|-s) 60 | compopt -o default ;; 61 | --working-directory|-D) 62 | compopt -o dirnames ;; 63 | --term|-t) 64 | command -v toe > /dev/null || return 1 65 | COMPREPLY=( $(compgen -W "$(toe -a | awk '$1 ~ /[+]/ {next}; {print $1}')" -- ${cur}) ) ;; 66 | --log-level|-d) 67 | COMPREPLY=( $(compgen -W "none error warning info" -- ${cur}) ) ;; 68 | --log-colorize|-l) 69 | COMPREPLY=( $(compgen -W "never always auto" -- ${cur}) ) ;; 70 | --app-id|--help|--override|--title|--version|--window-size-chars|--window-size-pixels|-[ahoTvWw]) 71 | # Don't autocomplete for these flags 72 | : ;; 73 | *) 74 | # Complete commands from $PATH 75 | COMPREPLY=( $(compgen -c -- ${cur}) ) ;; 76 | esac 77 | 78 | return 0 79 | } 80 | 81 | complete -F _footclient footclient 82 | -------------------------------------------------------------------------------- /completions/fish/foot.fish: -------------------------------------------------------------------------------- 1 | complete -c foot -x -a "(__fish_complete_subcommand)" 2 | complete -c foot -r -s c -l config -d "path to configuration file (XDG_CONFIG_HOME/foot/foot.ini)" 3 | complete -c foot -s C -l check-config -d "verify configuration and exit with 0 if ok, otherwise exit with 1" 4 | complete -c foot -x -s o -l override -d "configuration option to override, in form SECTION.KEY=VALUE" 5 | complete -c foot -x -s f -l font -a "(fc-list : family | sed 's/,/\n/g' | sort | uniq)" -d "font name and style in fontconfig format (monospace)" 6 | complete -c foot -x -s t -l term -a '(find /usr/share/terminfo -type f -printf "%f\n")' -d "value to set the environment variable TERM to (foot)" 7 | complete -c foot -x -s T -l title -d "initial window title" 8 | complete -c foot -x -s a -l app-id -d "value to set the app-id property on the Wayland window to (foot)" 9 | complete -c foot -s m -l maximized -d "start in maximized mode" 10 | complete -c foot -s F -l fullscreen -d "start in fullscreen mode" 11 | complete -c foot -s L -l login-shell -d "start shell as a login shell" 12 | complete -c foot -F -s D -l working-directory -d "initial working directory for the client application (CWD)" 13 | complete -c foot -x -s w -l window-size-pixels -d "window WIDTHxHEIGHT, in pixels (700x500)" 14 | complete -c foot -x -s W -l window-size-chars -d "window WIDTHxHEIGHT, in characters (not set)" 15 | complete -c foot -F -s s -l server -d "run as server; open terminals by running footclient" 16 | complete -c foot -s H -l hold -d "remain open after child process exits" 17 | complete -c foot -r -s p -l print-pid -d "print PID to this file or FD when up and running (server mode only)" 18 | complete -c foot -x -s d -l log-level -a "info warning error none" -d "log-level (warning)" 19 | complete -c foot -x -s l -l log-colorize -a "always never auto" -d "enable or disable colorization of log output on stderr" 20 | complete -c foot -s S -l log-no-syslog -d "disable syslog logging (server mode only)" 21 | complete -c foot -r -l pty -d "display an existing pty instead of creating one" 22 | complete -c foot -s v -l version -d "show the version number and quit" 23 | complete -c foot -s h -l help -d "show help message and quit" 24 | -------------------------------------------------------------------------------- /completions/fish/footclient.fish: -------------------------------------------------------------------------------- 1 | complete -c footclient -x -a "(__fish_complete_subcommand)" 2 | complete -c footclient -x -s t -l term -a '(find /usr/share/terminfo -type f -printf "%f\n")' -d "value to set the environment variable TERM to (foot)" 3 | complete -c footclient -x -s T -l title -d "initial window title" 4 | complete -c footclient -x -s a -l app-id -d "value to set the app-id property on the Wayland window to (foot)" 5 | complete -c footclient -s m -l maximized -d "start in maximized mode" 6 | complete -c footclient -s F -l fullscreen -d "start in fullscreen mode" 7 | complete -c footclient -s L -l login-shell -d "start shell as a login shell" 8 | complete -c footclient -F -s D -l working-directory -d "initial working directory for the client application (CWD)" 9 | complete -c footclient -x -s w -l window-size-pixels -d "window WIDTHxHEIGHT, in pixels (700x500)" 10 | complete -c footclient -x -s W -l window-size-chars -d "window WIDTHxHEIGHT, in characters (not set)" 11 | complete -c footclient -F -s s -l server-socket -d "override the default path to the foot server socket ($XDG_RUNTIME_DIR/foot-$WAYLAND_DISPLAY.sock)" 12 | complete -c footclient -s H -l hold -d "remain open after child process exits" 13 | complete -c footclient -s N -l no-wait -d "detach the client process from the running terminal, exiting immediately" 14 | complete -c footclient -x -s o -l override -d "configuration option to override, in form SECTION.KEY=VALUE" 15 | complete -c footclient -s E -l client-environment -d "child process inherits footclient's environment, instead of the server's" 16 | complete -c footclient -x -s d -l log-level -a "info warning error none" -d "log-level (info)" 17 | complete -c footclient -x -s l -l log-colorize -a "always never auto" -d "enable or disable colorization of log output on stderr" 18 | complete -c footclient -s v -l version -d "show the version number and quit" 19 | complete -c footclient -s h -l help -d "show help message and quit" 20 | -------------------------------------------------------------------------------- /completions/meson.build: -------------------------------------------------------------------------------- 1 | zsh_install_dir = join_paths(get_option('datadir'), 'zsh', 'site-functions') 2 | fish_install_dir = join_paths(get_option('datadir'), 'fish', 'vendor_completions.d') 3 | bash_install_dir = join_paths(get_option('datadir'), 'bash-completion', 'completions') 4 | install_data('zsh/_foot', install_dir: zsh_install_dir) 5 | install_data('zsh/_footclient', install_dir: zsh_install_dir) 6 | install_data('fish/foot.fish', install_dir: fish_install_dir) 7 | install_data('fish/footclient.fish', install_dir: fish_install_dir) 8 | install_data('bash/foot', install_dir: bash_install_dir) 9 | install_data('bash/footclient', install_dir: bash_install_dir) 10 | -------------------------------------------------------------------------------- /completions/zsh/_foot: -------------------------------------------------------------------------------- 1 | #compdef foot 2 | 3 | _arguments \ 4 | -s -S -C \ 5 | '(-c --config)'{-c,--config}'[path to configuration file (XDG_CONFIG_HOME/foot/foot.ini)]:config:_files' \ 6 | '(-C --check-config)'{-C,--check-config}'[verify configuration and exit with 0 if ok, otherwise exit with 1]' \ 7 | '(-o --override)'{-o,--override}'[configuration option to override, in form SECTION.KEY=VALUE]:()' \ 8 | '(-f --font)'{-f,--font}'[font name and style in fontconfig format (monospace)]:font:->fonts' \ 9 | '(-t --term)'{-t,--term}'[value to set the environment variable TERM to (foot)]:term:->terms' \ 10 | '(-T --title)'{-T,--title}'[initial window title]:()' \ 11 | '(-a --app-id)'{-a,--app-id}'[value to set the app-id property on the Wayland window to (foot)]:()' \ 12 | '(-m --maximized)'{-m,--maximized}'[start in maximized mode]' \ 13 | '(-F --fullscreen)'{-F,--fullscreen}'[start in fullscreen mode]' \ 14 | '(-L --login-shell)'{-L,--login-shell}'[start shell as a login shell]' \ 15 | '(-D --working-directory)'{-D,--working-directory}'[initial working directory for the client application (CWD)]:working_directory:_files' \ 16 | '(-w --window-size-pixels)'{-w,--window-size-pixels}'[window WIDTHxHEIGHT, in pixels (700x500)]:size_pixels:()' \ 17 | '(-W --window-size-chars)'{-W,--window-size-chars}'[window WIDTHxHEIGHT, in characters (not set)]:size_chars:()' \ 18 | '(-s --server)'{-s,--server}'[run as server; open terminals by running footclient]:server:_files' \ 19 | '(-H --hold)'{-H,--hold}'[remain open after child process exits]' \ 20 | '(-p --print-pid)'{-p,--print-pid}'[print PID to this file or FD when up and running (server mode only)]:pidfile:_files' \ 21 | '--pty=[display an existing pty instead of creating one]:pty:_files' \ 22 | '(-d --log-level)'{-d,--log-level}'[log level (warning)]:loglevel:(info warning error none)' \ 23 | '(-l --log-colorize)'{-l,--log-colorize}'[enable or disable colorization of log output on stderr]:logcolor:(never always auto)' \ 24 | '(-S --log-no-syslog)'{-s,--log-no-syslog}'[disable syslog logging (server mode only)]' \ 25 | '(-v --version)'{-v,--version}'[show the version number and quit]' \ 26 | '(-h --help)'{-h,--help}'[show help message and quit]' \ 27 | ':command: _command_names -e' \ 28 | '*::command arguments: _dispatch ${words[1]} ${words[1]}' 29 | 30 | case ${state} in 31 | fonts) 32 | IFS=$'\n' 33 | _values -s , 'font families' $(fc-list : family | sed 's/,/\n/g' | sort | uniq) 34 | unset IFS 35 | ;; 36 | 37 | terms) 38 | _values 'terminal definitions' /usr/share/terminfo/**/*(.:t) 39 | ;; 40 | esac 41 | -------------------------------------------------------------------------------- /completions/zsh/_footclient: -------------------------------------------------------------------------------- 1 | #compdef footclient 2 | 3 | _arguments \ 4 | -s -S -C \ 5 | '(-t --term)'{-t,--term}'[value to set the environment variable TERM to (foot)]:term:->terms' \ 6 | '(-T --title)'{-T,--title}'[initial window title]:()' \ 7 | '(-a --app-id)'{-a,--app-id}'[value to set the app-id property on the Wayland window to (foot)]:()' \ 8 | '(-m --maximized)'{-m,--maximized}'[start in maximized mode]' \ 9 | '(-F --fullscreen)'{-F,--fullscreen}'[start in fullscreen mode]' \ 10 | '(-L --login-shell)'{-L,--login-shell}'[start shell as a login shell]' \ 11 | '(-D --working-directory)'{-D,--working-directory}'[initial working directory for the client application (CWD)]:working_directory:_files' \ 12 | '(-w --window-size-pixels)'{-w,--window-size-pixels}'[window WIDTHxHEIGHT, in pixels (700x500)]:size_pixels:()' \ 13 | '(-W --window-size-chars)'{-W,--window-size-chars}'[window WIDTHxHEIGHT, in characters (not set)]:size_chars:()' \ 14 | '(-s --server-socket)'{-s,--server-socket}'[override the default path to the foot server socket ($XDG_RUNTIME_DIR/foot-$WAYLAND_DISPLAY.sock)]:server:_files' \ 15 | '(-H --hold)'{-H,--hold}'[remain open after child process exits]' \ 16 | '(-N --no-wait)'{-N,--no-wait}'[detach the client process from the running terminal, exiting immediately]' \ 17 | '(-o --override)'{-o,--override}'[configuration option to override, in form SECTION.KEY=VALUE]:()' \ 18 | '(-E --client-environment)'{-E,--client-environment}"[child process inherits footclient's environment, instead of the server's]" \ 19 | '(-d --log-level)'{-d,--log-level}'[log level (warning)]:loglevel:(info warning error none)' \ 20 | '(-l --log-colorize)'{-l,--log-colorize}'[enable or disable colorization of log output on stderr]:logcolor:(never always auto)' \ 21 | '(-v --version)'{-v,--version}'[show the version number and quit]' \ 22 | '(-h --help)'{-h,--help}'[show help message and quit]' \ 23 | ':command: _command_names -e' \ 24 | '*::command arguments: _dispatch ${words[1]} ${words[1]}' 25 | 26 | case ${state} in 27 | terms) 28 | _values 'terminal definitions' /usr/share/terminfo/**/*(.:t) 29 | ;; 30 | esac 31 | -------------------------------------------------------------------------------- /composed.c: -------------------------------------------------------------------------------- 1 | #include "composed.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "debug.h" 7 | 8 | struct composed * 9 | composed_lookup(struct composed *root, uint32_t key) 10 | { 11 | struct composed *node = root; 12 | 13 | while (node != NULL) { 14 | if (key == node->key) 15 | return node; 16 | 17 | node = key < node->key ? node->left : node->right; 18 | } 19 | 20 | return NULL; 21 | } 22 | 23 | void 24 | composed_insert(struct composed **root, struct composed *node) 25 | { 26 | node->left = node->right = NULL; 27 | 28 | if (*root == NULL) { 29 | *root = node; 30 | return; 31 | } 32 | 33 | uint32_t key = node->key; 34 | 35 | struct composed *prev = NULL; 36 | struct composed *n = *root; 37 | 38 | while (n != NULL) { 39 | xassert(n->key != node->key); 40 | 41 | prev = n; 42 | n = key < n->key ? n->left : n->right; 43 | } 44 | 45 | xassert(prev != NULL); 46 | xassert(n == NULL); 47 | 48 | if (key < prev->key) { 49 | xassert(prev->left == NULL); 50 | prev->left = node; 51 | } else { 52 | xassert(prev->right == NULL); 53 | prev->right = node; 54 | } 55 | } 56 | 57 | void 58 | composed_free(struct composed *root) 59 | { 60 | if (root == NULL) 61 | return; 62 | 63 | composed_free(root->left); 64 | composed_free(root->right); 65 | 66 | free(root->chars); 67 | free(root); 68 | } 69 | -------------------------------------------------------------------------------- /composed.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | struct composed { 7 | char32_t *chars; 8 | struct composed *left; 9 | struct composed *right; 10 | uint32_t key; 11 | uint8_t count; 12 | uint8_t width; 13 | }; 14 | 15 | struct composed *composed_lookup(struct composed *root, uint32_t key); 16 | void composed_insert(struct composed **root, struct composed *node); 17 | 18 | void composed_free(struct composed *root); 19 | -------------------------------------------------------------------------------- /csi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "terminal.h" 5 | 6 | void csi_dispatch(struct terminal *term, uint8_t final); 7 | -------------------------------------------------------------------------------- /cursor-shape.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define LOG_MODULE "cursor-shape" 5 | #define LOG_ENABLE_DBG 0 6 | #include "log.h" 7 | 8 | #include "cursor-shape.h" 9 | #include "debug.h" 10 | #include "util.h" 11 | 12 | const char *const * 13 | cursor_shape_to_string(enum cursor_shape shape) 14 | { 15 | static const char *const table[][CURSOR_SHAPE_COUNT]= { 16 | [CURSOR_SHAPE_NONE] = {NULL}, 17 | [CURSOR_SHAPE_HIDDEN] = {"hidden", NULL}, 18 | [CURSOR_SHAPE_LEFT_PTR] = {"default", "left_ptr", NULL}, 19 | [CURSOR_SHAPE_TEXT] = {"text", "xterm", NULL}, 20 | [CURSOR_SHAPE_TOP_LEFT_CORNER] = {"nw-resize", "top_left_corner", NULL}, 21 | [CURSOR_SHAPE_TOP_RIGHT_CORNER] = {"ne-resize", "top_right_corner", NULL}, 22 | [CURSOR_SHAPE_BOTTOM_LEFT_CORNER] = {"sw-resize", "bottom_left_corner", NULL}, 23 | [CURSOR_SHAPE_BOTTOM_RIGHT_CORNER] = {"se-resize", "bottom_right_corner", NULL}, 24 | [CURSOR_SHAPE_LEFT_SIDE] = {"w-resize", "left_side", NULL}, 25 | [CURSOR_SHAPE_RIGHT_SIDE] = {"e-resize", "right_side", NULL}, 26 | [CURSOR_SHAPE_TOP_SIDE] = {"n-resize", "top_side", NULL}, 27 | [CURSOR_SHAPE_BOTTOM_SIDE] = {"s-resize", "bottom_side", NULL}, 28 | 29 | }; 30 | 31 | xassert(shape <= ALEN(table)); 32 | return table[shape]; 33 | } 34 | 35 | enum wp_cursor_shape_device_v1_shape 36 | cursor_shape_to_server_shape(enum cursor_shape shape) 37 | { 38 | static const enum wp_cursor_shape_device_v1_shape table[CURSOR_SHAPE_COUNT] = { 39 | [CURSOR_SHAPE_LEFT_PTR] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT, 40 | [CURSOR_SHAPE_TEXT] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT, 41 | [CURSOR_SHAPE_TOP_LEFT_CORNER] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE, 42 | [CURSOR_SHAPE_TOP_RIGHT_CORNER] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE, 43 | [CURSOR_SHAPE_BOTTOM_LEFT_CORNER] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE, 44 | [CURSOR_SHAPE_BOTTOM_RIGHT_CORNER] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE, 45 | [CURSOR_SHAPE_LEFT_SIDE] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE, 46 | [CURSOR_SHAPE_RIGHT_SIDE] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE, 47 | [CURSOR_SHAPE_TOP_SIDE] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE, 48 | [CURSOR_SHAPE_BOTTOM_SIDE] = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE, 49 | }; 50 | 51 | xassert(shape <= ALEN(table)); 52 | xassert(table[shape] != 0); 53 | return table[shape]; 54 | } 55 | 56 | enum wp_cursor_shape_device_v1_shape 57 | cursor_string_to_server_shape(const char *xcursor) 58 | { 59 | if (xcursor == NULL) 60 | return 0; 61 | 62 | static const char *const table[][2] = { 63 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT] = {"default", "left_ptr"}, 64 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CONTEXT_MENU] = {"context-menu"}, 65 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_HELP] = {"help", "question_arrow"}, 66 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER] = {"pointer", "hand"}, 67 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_PROGRESS] = {"progress", "left_ptr_watch"}, 68 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_WAIT] = {"wait", "watch"}, 69 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CELL] = {"cell"}, 70 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR] = {"crosshair", "cross"}, 71 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT] = {"text", "xterm"}, 72 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_VERTICAL_TEXT] = {"vertical-text"}, 73 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALIAS] = {"alias", "dnd-link"}, 74 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COPY] = {"copy", "dnd-copy"}, 75 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE] = {"move"}, /* dnd-move? */ 76 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NO_DROP] = {"no-drop", "dnd-no-drop"}, 77 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED] = {"not-allowed", "crossed_circle"}, 78 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB] = {"grab", "hand1"}, 79 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRABBING] = {"grabbing"}, 80 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE] = {"e-resize", "right_side"}, 81 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE] = {"n-resize", "top_side"}, 82 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE] = {"ne-resize", "top_right_corner"}, 83 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE] = {"nw-resize", "top_left_corner"}, 84 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE] = {"s-resize", "bottom_side"}, 85 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE] = {"se-resize", "bottom_right_corner"}, 86 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE] = {"sw-resize", "bottom_left_corner"}, 87 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE] = {"w-resize", "left_side"}, 88 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE] = {"ew-resize", "sb_h_double_arrow"}, 89 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE] = {"ns-resize", "sb_v_double_arrow"}, 90 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE] = {"nesw-resize", "fd_double_arrow"}, 91 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE] = {"nwse-resize", "bd_double_arrow"}, 92 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COL_RESIZE] = {"col-resize", "sb_h_double_arrow"}, 93 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ROW_RESIZE] = {"row-resize", "sb_v_double_arrow"}, 94 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_SCROLL] = {"all-scroll", "fleur"}, 95 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_IN] = {"zoom-in"}, 96 | [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT] = {"zoom-out"}, 97 | }; 98 | 99 | for (size_t i = 0; i < ALEN(table); i++) { 100 | for (size_t j = 0; j < ALEN(table[i]); j++) { 101 | if (table[i][j] != NULL && streq(xcursor, table[i][j])) { 102 | return i; 103 | } 104 | } 105 | } 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /cursor-shape.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | enum cursor_shape { 6 | CURSOR_SHAPE_NONE, 7 | CURSOR_SHAPE_CUSTOM, 8 | CURSOR_SHAPE_HIDDEN, 9 | 10 | CURSOR_SHAPE_LEFT_PTR, 11 | CURSOR_SHAPE_TEXT, 12 | CURSOR_SHAPE_TOP_LEFT_CORNER, 13 | CURSOR_SHAPE_TOP_RIGHT_CORNER, 14 | CURSOR_SHAPE_BOTTOM_LEFT_CORNER, 15 | CURSOR_SHAPE_BOTTOM_RIGHT_CORNER, 16 | CURSOR_SHAPE_LEFT_SIDE, 17 | CURSOR_SHAPE_RIGHT_SIDE, 18 | CURSOR_SHAPE_TOP_SIDE, 19 | CURSOR_SHAPE_BOTTOM_SIDE, 20 | 21 | CURSOR_SHAPE_COUNT, 22 | }; 23 | 24 | const char *const *cursor_shape_to_string(enum cursor_shape shape); 25 | 26 | enum wp_cursor_shape_device_v1_shape cursor_shape_to_server_shape( 27 | enum cursor_shape shape); 28 | enum wp_cursor_shape_device_v1_shape cursor_string_to_server_shape( 29 | const char *xcursor); 30 | -------------------------------------------------------------------------------- /dcs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "terminal.h" 5 | 6 | void dcs_hook(struct terminal *term, uint8_t final); 7 | void dcs_put(struct terminal *term, uint8_t c); 8 | void dcs_unhook(struct terminal *term); 9 | -------------------------------------------------------------------------------- /debug.c: -------------------------------------------------------------------------------- 1 | #include "debug.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "log.h" 9 | 10 | #if defined(__SANITIZE_ADDRESS__) || HAS_FEATURE(address_sanitizer) 11 | #include 12 | #define ASAN_ENABLED 1 13 | #endif 14 | 15 | static void 16 | print_stack_trace(void) 17 | { 18 | #ifdef ASAN_ENABLED 19 | fputs("\nStack trace:\n", stderr); 20 | __sanitizer_print_stack_trace(); 21 | #endif 22 | } 23 | 24 | noreturn void 25 | fatal_error(const char *file, int line, const char *msg, int err) 26 | { 27 | log_msg(LOG_CLASS_ERROR, "debug", file, line, "%s: %s", msg, strerror(err)); 28 | print_stack_trace(); 29 | fflush(stderr); 30 | abort(); 31 | } 32 | 33 | noreturn void 34 | bug(const char *file, int line, const char *func, const char *fmt, ...) 35 | { 36 | char buf[4096]; 37 | va_list ap; 38 | va_start(ap, fmt); 39 | int n = vsnprintf(buf, sizeof(buf), fmt, ap); 40 | va_end(ap); 41 | 42 | const char *msg = likely(n >= 0) ? buf : "??"; 43 | log_msg(LOG_CLASS_ERROR, "debug", file, line, "BUG in %s(): %s", func, msg); 44 | print_stack_trace(); 45 | fflush(stderr); 46 | abort(); 47 | } 48 | -------------------------------------------------------------------------------- /debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "macros.h" 4 | 5 | #define FATAL_ERROR(...) fatal_error(__FILE__, __LINE__, __VA_ARGS__) 6 | 7 | #ifdef NDEBUG 8 | #define BUG(...) UNREACHABLE() 9 | #else 10 | #define BUG(...) bug(__FILE__, __LINE__, __func__, __VA_ARGS__) 11 | #endif 12 | 13 | #define xassert(x) do { \ 14 | IGNORE_WARNING("-Wtautological-compare") \ 15 | if (unlikely(!(x))) { \ 16 | BUG("assertion failed: '%s'", #x); \ 17 | } \ 18 | UNIGNORE_WARNINGS \ 19 | } while (0) 20 | 21 | #ifndef static_assert 22 | #if __STDC_VERSION__ >= 201112L 23 | #define static_assert(x, msg) _Static_assert((x), msg) 24 | #elif GNUC_AT_LEAST(4, 6) || HAS_EXTENSION(c_static_assert) 25 | #define static_assert(x, msg) __extension__ _Static_assert((x), msg) 26 | #else 27 | #define static_assert(x, msg) 28 | #endif 29 | #endif 30 | 31 | noreturn void fatal_error(const char *file, int line, const char *msg, int err) COLD; 32 | noreturn void bug(const char *file, int line, const char *func, const char *fmt, ...) PRINTF(4) COLD; 33 | -------------------------------------------------------------------------------- /doc/benchmark.md: -------------------------------------------------------------------------------- 1 | # Benchmarks 2 | 3 | ## vtebench 4 | 5 | All benchmarks are done using [vtebench](https://github.com/alacritty/vtebench): 6 | 7 | ```sh 8 | ./target/release/vtebench -b ./benchmarks --dat /tmp/ 9 | ``` 10 | 11 | ## 2022-05-12 12 | 13 | ### System 14 | 15 | CPU: i9-9900 16 | 17 | RAM: 64GB 18 | 19 | Graphics: Radeon RX 5500XT 20 | 21 | 22 | ### Terminal configuration 23 | 24 | Geometry: 2040x1884 25 | 26 | Font: Fantasque Sans Mono 10.00pt/23px 27 | 28 | Scrollback: 10000 lines 29 | 30 | 31 | ### Results 32 | 33 | | Benchmark (times in ms) | Foot (GCC+PGO) 1.12.1 | Foot 1.12.1 | Alacritty 0.10.1 | URxvt 9.26 | XTerm 372 | 34 | |-------------------------------|----------------------:|------------:|-----------------:|-----------:|----------:| 35 | | cursor motion | 10.40 | 14.07 | 24.97 | 23.38 | 1622.86 | 36 | | dense cells | 29.58 | 45.46 | 97.45 | 10828.00 | 2323.00 | 37 | | light cells | 4.34 | 4.40 | 12.84 | 12.17 | 49.81 | 38 | | scrollling | 135.31 | 116.35 | 121.69 | 108.30 | 4041.33 | 39 | | scrolling bottom region | 118.19 | 109.70 | 105.26 | 118.80 | 3875.00 | 40 | | scrolling bottom small region | 132.41 | 122.11 | 122.83 | 151.30 | 3839.67 | 41 | | scrolling fullscreen | 5.70 | 5.66 | 10.92 | 12.09 | 124.25 | 42 | | scrolling top region | 144.19 | 121.78 | 135.81 | 159.24 | 3858.33 | 43 | | scrolling top small region | 135.95 | 119.01 | 115.46 | 216.55 | 3872.67 | 44 | | unicode | 11.56 | 10.92 | 15.94 | 1012.27 | 4779.33 | 45 | 46 | 47 | ## 2022-05-12 48 | 49 | ### System 50 | 51 | CPU: i5-8250U 52 | 53 | RAM: 8GB 54 | 55 | Graphics: Intel UHD Graphics 620 56 | 57 | 58 | ### Terminal configuration 59 | 60 | Geometry: 945x1020 61 | 62 | Font: Dina:pixelsize=12 63 | 64 | Scrollback=10000 lines 65 | 66 | 67 | ### Results 68 | 69 | 70 | | Benchmark (times in ms) | Foot (GCC+PGO) 1.12.1 | Foot 1.12.1 | Alacritty 0.10.1 | URxvt 9.26 | XTerm 372 | 71 | |-------------------------------|----------------------:|------------:|-----------------:|-----------:|----------:| 72 | | cursor motion | 15.03 | 16.74 | 23.22 | 24.14 | 1381.63 | 73 | | dense cells | 43.56 | 54.10 | 89.43 | 1807.17 | 1945.50 | 74 | | light cells | 7.96 | 9.66 | 20.19 | 21.31 | 122.44 | 75 | | scrollling | 146.02 | 150.47 | 129.22 | 129.84 | 10140.00 | 76 | | scrolling bottom region | 138.36 | 137.42 | 117.06 | 141.87 | 10136.00 | 77 | | scrolling bottom small region | 137.40 | 134.66 | 128.97 | 208.77 | 9930.00 | 78 | | scrolling fullscreen | 11.66 | 12.02 | 19.69 | 21.96 | 315.80 | 79 | | scrolling top region | 143.81 | 133.47 | 132.51 | 475.81 | 10267.00 | 80 | | scrolling top small region | 133.72 | 135.32 | 145.10 | 314.13 | 10074.00 | 81 | | unicode | 20.89 | 21.78 | 26.11 | 5687.00 | 15740.00 | 82 | -------------------------------------------------------------------------------- /doc/meson.build: -------------------------------------------------------------------------------- 1 | scdoc_prog = find_program(scdoc.get_variable('scdoc'), native: true) 2 | 3 | if utmp_backend != 'none' 4 | utmp_add_args = '@0@ $WAYLAND_DISPLAY'.format(utmp_add) 5 | utmp_del_args = (utmp_del_have_argument 6 | ? '@0@ $WAYLAND_DISPLAY'.format(utmp_del) 7 | : '@0@'.format(utmp_del)) 8 | utmp_path = utmp_default_helper_path 9 | else 10 | utmp_add_args = '' 11 | utmp_del_args = '' 12 | utmp_path = 'none' 13 | endif 14 | 15 | 16 | conf_data = configuration_data( 17 | { 18 | 'default_terminfo': get_option('default-terminfo'), 19 | 'utmp_backend': utmp_backend, 20 | 'utmp_add_args': utmp_add_args, 21 | 'utmp_del_args': utmp_del_args, 22 | 'utmp_helper_path': utmp_path, 23 | } 24 | ) 25 | 26 | foreach man_src : [{'name': 'foot', 'section' : 1}, 27 | {'name': 'foot.ini', 'section': 5}, 28 | {'name': 'footclient', 'section': 1}, 29 | {'name': 'foot-ctlseqs', 'section': 7}] 30 | name = man_src['name'] 31 | section = man_src['section'] 32 | out = '@0@.@1@'.format(name, section) 33 | 34 | preprocessed = configure_file( 35 | input: '@0@.@1@.scd'.format(name, section), 36 | output: '@0@.preprocessed'.format(out), 37 | configuration: conf_data, 38 | ) 39 | 40 | custom_target( 41 | out, 42 | output: out, 43 | input: preprocessed, 44 | command: scdoc_prog.full_path(), 45 | capture: true, 46 | feed: true, 47 | install: true, 48 | install_dir: join_paths(get_option('mandir'), 'man@0@'.format(section))) 49 | endforeach 50 | -------------------------------------------------------------------------------- /doc/sixel-wow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanteAlighierin/foot/a42fec49280b2d8775dcfe4c879f6fcd8dd4d8e5/doc/sixel-wow.png -------------------------------------------------------------------------------- /extract.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "terminal.h" 8 | 9 | struct extraction_context; 10 | 11 | struct extraction_context *extract_begin( 12 | enum selection_kind kind, bool strip_trailing_empty); 13 | 14 | bool extract_one( 15 | const struct terminal *term, const struct row *row, const struct cell *cell, 16 | int col, void *context); 17 | 18 | bool extract_finish( 19 | struct extraction_context *context, char **text, size_t *len); 20 | bool extract_finish_wide( 21 | struct extraction_context *context, char32_t **text, size_t *len); 22 | -------------------------------------------------------------------------------- /fdm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct fdm; 6 | 7 | typedef bool (*fdm_fd_handler_t)(struct fdm *fdm, int fd, int events, void *data); 8 | typedef bool (*fdm_signal_handler_t)(struct fdm *fdm, int signo, void *data); 9 | typedef void (*fdm_hook_t)(struct fdm *fdm, void *data); 10 | 11 | enum fdm_hook_priority { 12 | FDM_HOOK_PRIORITY_LOW, 13 | FDM_HOOK_PRIORITY_NORMAL, 14 | FDM_HOOK_PRIORITY_HIGH 15 | }; 16 | 17 | struct fdm *fdm_init(void); 18 | void fdm_destroy(struct fdm *fdm); 19 | 20 | bool fdm_add(struct fdm *fdm, int fd, int events, fdm_fd_handler_t handler, void *data); 21 | bool fdm_del(struct fdm *fdm, int fd); 22 | bool fdm_del_no_close(struct fdm *fdm, int fd); 23 | 24 | bool fdm_event_add(struct fdm *fdm, int fd, int events); 25 | bool fdm_event_del(struct fdm *fdm, int fd, int events); 26 | 27 | bool fdm_hook_add(struct fdm *fdm, fdm_hook_t hook, void *data, 28 | enum fdm_hook_priority priority); 29 | bool fdm_hook_del(struct fdm *fdm, fdm_hook_t hook, enum fdm_hook_priority priority); 30 | 31 | bool fdm_signal_add(struct fdm *fdm, int signo, fdm_signal_handler_t handler, void *data); 32 | bool fdm_signal_del(struct fdm *fdm, int signo); 33 | 34 | bool fdm_poll(struct fdm *fdm); 35 | -------------------------------------------------------------------------------- /foot-features.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | static inline bool feature_assertions(void) 6 | { 7 | #if defined(NDEBUG) 8 | return false; 9 | #else 10 | return true; 11 | #endif 12 | } 13 | 14 | static inline bool feature_ime(void) 15 | { 16 | #if defined(FOOT_IME_ENABLED) && FOOT_IME_ENABLED 17 | return true; 18 | #else 19 | return false; 20 | #endif 21 | } 22 | 23 | static inline bool feature_pgo(void) 24 | { 25 | #if defined(FOOT_PGO_ENABLED) && FOOT_PGO_ENABLED 26 | return true; 27 | #else 28 | return false; 29 | #endif 30 | } 31 | 32 | static inline bool feature_graphemes(void) 33 | { 34 | #if defined(FOOT_GRAPHEME_CLUSTERING) && FOOT_GRAPHEME_CLUSTERING 35 | return true; 36 | #else 37 | return false; 38 | #endif 39 | } 40 | 41 | static inline bool feature_xdg_toplevel_icon(void) 42 | { 43 | #if defined(HAVE_XDG_TOPLEVEL_ICON) 44 | return true; 45 | #else 46 | return false; 47 | #endif 48 | } 49 | -------------------------------------------------------------------------------- /foot-server.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Exec=foot --server 4 | Icon=foot 5 | Terminal=false 6 | Categories=System;TerminalEmulator; 7 | Keywords=shell;prompt;command;commandline; 8 | 9 | Name=Foot Server 10 | GenericName=Terminal 11 | Comment=A wayland native terminal emulator (server) 12 | -------------------------------------------------------------------------------- /foot-server.service.in: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart=@bindir@/foot --server=3 3 | UnsetEnvironment=LISTEN_PID LISTEN_FDS LISTEN_FDNAMES 4 | NonBlocking=true 5 | 6 | [Unit] 7 | Requires=%N.socket 8 | Description=Foot terminal server mode 9 | Documentation=man:foot(1) 10 | PartOf=graphical-session.target 11 | After=graphical-session.target 12 | ConditionEnvironment=WAYLAND_DISPLAY 13 | 14 | [Install] 15 | WantedBy=graphical-session.target 16 | -------------------------------------------------------------------------------- /foot-server.socket: -------------------------------------------------------------------------------- 1 | [Socket] 2 | ListenStream=%t/foot.sock 3 | 4 | [Unit] 5 | PartOf=graphical-session.target 6 | After=graphical-session.target 7 | ConditionEnvironment=WAYLAND_DISPLAY 8 | 9 | [Install] 10 | WantedBy=graphical-session.target 11 | -------------------------------------------------------------------------------- /foot.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Exec=foot 4 | Icon=foot 5 | Terminal=false 6 | Categories=System;TerminalEmulator; 7 | Keywords=shell;prompt;command;commandline; 8 | 9 | Name=Foot 10 | GenericName=Terminal 11 | Comment=A wayland native terminal emulator 12 | -------------------------------------------------------------------------------- /footclient.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Exec=footclient 4 | Icon=foot 5 | Terminal=false 6 | Categories=System;TerminalEmulator; 7 | Keywords=shell;prompt;command;commandline; 8 | 9 | Name=Foot Client 10 | GenericName=Terminal 11 | Comment=A wayland native terminal emulator (client) 12 | -------------------------------------------------------------------------------- /generate-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | if [ ${#} -ne 3 ]; then 6 | echo "Usage: ${0} " 7 | exit 1 8 | fi 9 | 10 | default_version=${1} 11 | src_dir=${2} 12 | out_file=${3} 13 | 14 | # echo "default version: ${default_version}" 15 | # echo "source directory: ${src_dir}" 16 | # echo "output file: ${out_file}" 17 | 18 | if [ -d "${src_dir}/.git" ] && command -v git > /dev/null; then 19 | workdir=$(pwd) 20 | cd "${src_dir}" 21 | 22 | if git describe --tags > /dev/null 2>&1; then 23 | git_version=$(git describe --always --tags) 24 | else 25 | # No tags available, happens in e.g. CI builds 26 | git_version="${default_version}" 27 | fi 28 | 29 | git_branch=$(git rev-parse --abbrev-ref HEAD) 30 | cd "${workdir}" 31 | 32 | new_version="${git_version} ($(date "+%b %d %Y"), branch '${git_branch}')" 33 | else 34 | new_version="${default_version}" 35 | extra="" 36 | fi 37 | 38 | major=$(echo "${new_version}" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1/') 39 | minor=$(echo "${new_version}" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\2/') 40 | patch=$(echo "${new_version}" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\3/') 41 | extra=$(echo "${new_version}" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+)(-([0-9]+-g[a-z0-9]+) .*)?.*/\5/') 42 | 43 | new_version="#define FOOT_VERSION \"${new_version}\" 44 | #define FOOT_MAJOR ${major} 45 | #define FOOT_MINOR ${minor} 46 | #define FOOT_PATCH ${patch} 47 | #define FOOT_EXTRA \"${extra}\"" 48 | 49 | if [ -f "${out_file}" ]; then 50 | old_version=$(cat "${out_file}") 51 | else 52 | old_version="" 53 | fi 54 | 55 | # echo "old version: ${old_version}" 56 | # echo "new version: ${new_version}" 57 | 58 | if [ "${old_version}" != "${new_version}" ]; then 59 | echo "${new_version}" > "${out_file}" 60 | fi 61 | -------------------------------------------------------------------------------- /grid.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "debug.h" 5 | #include "terminal.h" 6 | 7 | struct grid *grid_snapshot(const struct grid *grid); 8 | void grid_free(struct grid *grid); 9 | 10 | void grid_swap_row(struct grid *grid, int row_a, int row_b); 11 | struct row *grid_row_alloc(int cols, bool initialize); 12 | void grid_row_free(struct row *row); 13 | 14 | void grid_resize_without_reflow( 15 | struct grid *grid, int new_rows, int new_cols, 16 | int old_screen_rows, int new_screen_rows); 17 | 18 | void grid_resize_and_reflow( 19 | struct grid *grid, int new_rows, int new_cols, 20 | int old_screen_rows, int new_screen_rows, 21 | size_t tracking_points_count, 22 | struct coord *const _tracking_points[static tracking_points_count]); 23 | 24 | /* Convert row numbers between scrollback-relative and absolute coordinates */ 25 | int grid_row_abs_to_sb(const struct grid *grid, int screen_rows, int abs_row); 26 | int grid_row_sb_to_abs(const struct grid *grid, int screen_rows, int sb_rel_row); 27 | 28 | int grid_sb_start_ignore_uninitialized(const struct grid *grid, int screen_rows); 29 | int grid_row_abs_to_sb_precalc_sb_start( 30 | const struct grid *grid, int sb_start, int abs_row); 31 | int grid_row_sb_to_abs_precalc_sb_start( 32 | const struct grid *grid, int sb_start, int sb_rel_row); 33 | 34 | static inline int 35 | grid_row_absolute(const struct grid *grid, int row_no) 36 | { 37 | return (grid->offset + row_no) & (grid->num_rows - 1); 38 | } 39 | 40 | static inline int 41 | grid_row_absolute_in_view(const struct grid *grid, int row_no) 42 | { 43 | return (grid->view + row_no) & (grid->num_rows - 1); 44 | } 45 | 46 | static inline struct row * 47 | _grid_row_maybe_alloc(struct grid *grid, int row_no, bool alloc_if_null) 48 | { 49 | xassert(grid->offset >= 0); 50 | 51 | int real_row = grid_row_absolute(grid, row_no); 52 | struct row *row = grid->rows[real_row]; 53 | 54 | if (row == NULL && alloc_if_null) { 55 | row = grid_row_alloc(grid->num_cols, false); 56 | grid->rows[real_row] = row; 57 | } 58 | 59 | xassert(row != NULL); 60 | return row; 61 | } 62 | 63 | static inline struct row * 64 | grid_row(struct grid *grid, int row_no) 65 | { 66 | return _grid_row_maybe_alloc(grid, row_no, false); 67 | } 68 | 69 | static inline struct row * 70 | grid_row_and_alloc(struct grid *grid, int row_no) 71 | { 72 | return _grid_row_maybe_alloc(grid, row_no, true); 73 | } 74 | 75 | static inline struct row * 76 | grid_row_in_view(struct grid *grid, int row_no) 77 | { 78 | xassert(grid->view >= 0); 79 | 80 | int real_row = grid_row_absolute_in_view(grid, row_no); 81 | struct row *row = grid->rows[real_row]; 82 | 83 | xassert(row != NULL); 84 | return row; 85 | } 86 | 87 | void grid_row_uri_range_put( 88 | struct row *row, int col, const char *uri, uint64_t id); 89 | void grid_row_uri_range_erase(struct row *row, int start, int end); 90 | 91 | void grid_row_underline_range_put( 92 | struct row *row, int col, struct underline_range_data data); 93 | void grid_row_underline_range_erase(struct row *row, int start, int end); 94 | 95 | static inline void 96 | grid_row_uri_range_destroy(struct row_range *range) 97 | { 98 | free(range->uri.uri); 99 | } 100 | 101 | static inline void 102 | grid_row_underline_range_destroy(struct row_range *range) 103 | { 104 | } 105 | 106 | static inline void 107 | grid_row_range_destroy(struct row_range *range, enum row_range_type type) 108 | { 109 | switch (type) { 110 | case ROW_RANGE_URI: grid_row_uri_range_destroy(range); break; 111 | case ROW_RANGE_UNDERLINE: grid_row_underline_range_destroy(range); break; 112 | } 113 | } 114 | 115 | static inline void 116 | grid_row_ranges_destroy(struct row_ranges *ranges, enum row_range_type type) 117 | { 118 | for (int i = 0; i < ranges->count; i++) { 119 | grid_row_range_destroy(&ranges->v[i], type); 120 | } 121 | } 122 | 123 | static inline void 124 | grid_row_reset_extra(struct row *row) 125 | { 126 | struct row_data *extra = row->extra; 127 | 128 | if (likely(extra == NULL)) 129 | return; 130 | 131 | grid_row_ranges_destroy(&extra->uri_ranges, ROW_RANGE_URI); 132 | grid_row_ranges_destroy(&extra->underline_ranges, ROW_RANGE_UNDERLINE); 133 | free(extra->uri_ranges.v); 134 | free(extra->underline_ranges.v); 135 | 136 | free(extra); 137 | row->extra = NULL; 138 | } 139 | -------------------------------------------------------------------------------- /hsl.c: -------------------------------------------------------------------------------- 1 | #include "hsl.h" 2 | 3 | #include 4 | 5 | #include "util.h" 6 | 7 | void 8 | rgb_to_hsl(uint32_t rgb, int *hue, int *sat, int *lum) 9 | { 10 | double r = (double)((rgb >> 16) & 0xff) / 255.; 11 | double g = (double)((rgb >> 8) & 0xff) / 255.; 12 | double b = (double)((rgb >> 0) & 0xff) / 255.; 13 | 14 | double x_max = max(max(r, g), b); 15 | double x_min = min(min(r, g), b); 16 | double V = x_max; 17 | 18 | double C = x_max - x_min; 19 | double L = (x_max + x_min) / 2.; 20 | 21 | *lum = 100 * L; 22 | 23 | if (C == 0.0) 24 | *hue = 0; 25 | else if (V == r) 26 | *hue = 60. * (0. + (g - b) / C); 27 | else if (V == g) 28 | *hue = 60. * (2. + (b - r) / C); 29 | else if (V == b) 30 | *hue = 60. * (4. + (r - g) / C); 31 | if (*hue < 0) 32 | *hue += 360; 33 | 34 | double S = C == 0.0 35 | ? 0 36 | : C / (1. - fabs(2. * L - 1.)); 37 | *sat = 100 * S; 38 | } 39 | 40 | uint32_t 41 | hsl_to_rgb(int hue, int sat, int lum) 42 | { 43 | double L = lum / 100.0; 44 | double S = sat / 100.0; 45 | double C = (1. - fabs(2. * L - 1.)) * S; 46 | 47 | double X = C * (1. - fabs(fmod((double)hue / 60., 2.) - 1.)); 48 | double m = L - C / 2.; 49 | 50 | double r, g, b; 51 | if (hue >= 0 && hue <= 60) { 52 | r = C; 53 | g = X; 54 | b = 0.; 55 | } else if (hue >= 60 && hue <= 120) { 56 | r = X; 57 | g = C; 58 | b = 0.; 59 | } else if (hue >= 120 && hue <= 180) { 60 | r = 0.; 61 | g = C; 62 | b = X; 63 | } else if (hue >= 180 && hue <= 240) { 64 | r = 0.; 65 | g = X; 66 | b = C; 67 | } else if (hue >= 240 && hue <= 300) { 68 | r = X; 69 | g = 0.; 70 | b = C; 71 | } else if (hue >= 300 && hue <= 360) { 72 | r = C; 73 | g = 0.; 74 | b = X; 75 | } else { 76 | r = 0.; 77 | g = 0.; 78 | b = 0.; 79 | } 80 | 81 | r += m; 82 | g += m; 83 | b += m; 84 | 85 | return ( 86 | (uint8_t)round(r * 255.) << 16 | 87 | (uint8_t)round(g * 255.) << 8 | 88 | (uint8_t)round(b * 255.) << 0); 89 | } 90 | -------------------------------------------------------------------------------- /hsl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void rgb_to_hsl(uint32_t rgb, int *hue, int *sat, int *lum); 6 | uint32_t hsl_to_rgb(int hue, int sat, int lum); 7 | -------------------------------------------------------------------------------- /icons/hicolor/48x48/apps/foot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanteAlighierin/foot/a42fec49280b2d8775dcfe4c879f6fcd8dd4d8e5/icons/hicolor/48x48/apps/foot.png -------------------------------------------------------------------------------- /icons/hicolor/scalable/apps/foot.svg: -------------------------------------------------------------------------------- 1 | 2 | 6 | foot logo 7 | 8 | 9 | 10 | 11 | 12 | 13 | image/svg+xml 14 | 16 | 17 | 18 | Lennard Hofmann 19 | 20 | 21 | https://freesvg.org/human-footprints 22 | 24 | foot logo 25 | 26 | 27 | terminal emulator 28 | footprint 29 | 30 | 31 | 2020-06-23 32 | Black square representing a terminal showing a human footprint as a prompt symbol and an underscore as the cursor 33 | 34 | 35 | 36 | 42 | 48 | 50 | 54 | 56 | 61 | 66 | 71 | 76 | 81 | 82 | 83 | 88 | 89 | -------------------------------------------------------------------------------- /icons/meson.build: -------------------------------------------------------------------------------- 1 | install_subdir('hicolor', install_dir : join_paths(get_option('datadir'), 'icons')) 2 | -------------------------------------------------------------------------------- /ime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(FOOT_IME_ENABLED) && FOOT_IME_ENABLED 4 | 5 | #include "text-input-unstable-v3.h" 6 | 7 | extern const struct zwp_text_input_v3_listener text_input_listener; 8 | 9 | #endif /* FOOT_IME_ENABLED */ 10 | 11 | struct seat; 12 | struct terminal; 13 | 14 | void ime_enable(struct seat *seat); 15 | void ime_disable(struct seat *seat); 16 | void ime_update_cursor_rect(struct seat *seat); 17 | 18 | void ime_reset_pending(struct seat *seat); 19 | void ime_reset_preedit(struct seat *seat); 20 | -------------------------------------------------------------------------------- /input.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "cursor-shape.h" 7 | #include "misc.h" 8 | #include "wayland.h" 9 | 10 | /* 11 | * Custom defines for mouse wheel left/right buttons. 12 | * 13 | * Libinput does not define these. On Wayland, all scroll events (both 14 | * vertical and horizontal) are reported not as buttons, as 'axis' 15 | * events. 16 | * 17 | * Libinput _does_ define BTN_BACK and BTN_FORWARD, which is 18 | * what we use for vertical scroll events. But for horizontal scroll 19 | * events, there aren't any pre-defined mouse buttons. 20 | * 21 | * Mouse buttons are in the range 0x110 - 0x11f, with joystick defines 22 | * starting at 0x120. 23 | */ 24 | #define BTN_WHEEL_BACK 0x11c 25 | #define BTN_WHEEL_FORWARD 0x11d 26 | #define BTN_WHEEL_LEFT 0x11e 27 | #define BTN_WHEEL_RIGHT 0x11f 28 | 29 | extern const struct wl_keyboard_listener keyboard_listener; 30 | extern const struct wl_pointer_listener pointer_listener; 31 | extern const struct wl_touch_listener touch_listener; 32 | 33 | void input_repeat(struct seat *seat, uint32_t key); 34 | 35 | void get_current_modifiers(const struct seat *seat, 36 | xkb_mod_mask_t *effective, 37 | xkb_mod_mask_t *consumed, 38 | uint32_t key, bool filter_locked); 39 | 40 | enum cursor_shape xcursor_for_csd_border(struct terminal *term, int x, int y); 41 | -------------------------------------------------------------------------------- /key-binding.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "config.h" 9 | 10 | enum bind_action_normal { 11 | BIND_ACTION_NONE, 12 | BIND_ACTION_NOOP, 13 | BIND_ACTION_SCROLLBACK_UP_PAGE, 14 | BIND_ACTION_SCROLLBACK_UP_HALF_PAGE, 15 | BIND_ACTION_SCROLLBACK_UP_LINE, 16 | BIND_ACTION_SCROLLBACK_DOWN_PAGE, 17 | BIND_ACTION_SCROLLBACK_DOWN_HALF_PAGE, 18 | BIND_ACTION_SCROLLBACK_DOWN_LINE, 19 | BIND_ACTION_SCROLLBACK_HOME, 20 | BIND_ACTION_SCROLLBACK_END, 21 | BIND_ACTION_CLIPBOARD_COPY, 22 | BIND_ACTION_CLIPBOARD_PASTE, 23 | BIND_ACTION_PRIMARY_PASTE, 24 | BIND_ACTION_SEARCH_START, 25 | BIND_ACTION_FONT_SIZE_UP, 26 | BIND_ACTION_FONT_SIZE_DOWN, 27 | BIND_ACTION_FONT_SIZE_RESET, 28 | BIND_ACTION_SPAWN_TERMINAL, 29 | BIND_ACTION_MINIMIZE, 30 | BIND_ACTION_MAXIMIZE, 31 | BIND_ACTION_FULLSCREEN, 32 | BIND_ACTION_PIPE_SCROLLBACK, 33 | BIND_ACTION_PIPE_VIEW, 34 | BIND_ACTION_PIPE_SELECTED, 35 | BIND_ACTION_PIPE_COMMAND_OUTPUT, 36 | BIND_ACTION_SHOW_URLS_COPY, 37 | BIND_ACTION_SHOW_URLS_LAUNCH, 38 | BIND_ACTION_SHOW_URLS_PERSISTENT, 39 | BIND_ACTION_TEXT_BINDING, 40 | BIND_ACTION_PROMPT_PREV, 41 | BIND_ACTION_PROMPT_NEXT, 42 | BIND_ACTION_UNICODE_INPUT, 43 | BIND_ACTION_QUIT, 44 | 45 | /* Mouse specific actions - i.e. they require a mouse coordinate */ 46 | BIND_ACTION_SCROLLBACK_UP_MOUSE, 47 | BIND_ACTION_SCROLLBACK_DOWN_MOUSE, 48 | BIND_ACTION_SELECT_BEGIN, 49 | BIND_ACTION_SELECT_BEGIN_BLOCK, 50 | BIND_ACTION_SELECT_EXTEND, 51 | BIND_ACTION_SELECT_EXTEND_CHAR_WISE, 52 | BIND_ACTION_SELECT_WORD, 53 | BIND_ACTION_SELECT_WORD_WS, 54 | BIND_ACTION_SELECT_QUOTE, 55 | BIND_ACTION_SELECT_ROW, 56 | 57 | BIND_ACTION_KEY_COUNT = BIND_ACTION_QUIT + 1, 58 | BIND_ACTION_COUNT = BIND_ACTION_SELECT_ROW + 1, 59 | }; 60 | 61 | enum bind_action_search { 62 | BIND_ACTION_SEARCH_NONE, 63 | BIND_ACTION_SEARCH_SCROLLBACK_UP_PAGE, 64 | BIND_ACTION_SEARCH_SCROLLBACK_UP_HALF_PAGE, 65 | BIND_ACTION_SEARCH_SCROLLBACK_UP_LINE, 66 | BIND_ACTION_SEARCH_SCROLLBACK_DOWN_PAGE, 67 | BIND_ACTION_SEARCH_SCROLLBACK_DOWN_HALF_PAGE, 68 | BIND_ACTION_SEARCH_SCROLLBACK_DOWN_LINE, 69 | BIND_ACTION_SEARCH_SCROLLBACK_HOME, 70 | BIND_ACTION_SEARCH_SCROLLBACK_END, 71 | BIND_ACTION_SEARCH_CANCEL, 72 | BIND_ACTION_SEARCH_COMMIT, 73 | BIND_ACTION_SEARCH_FIND_PREV, 74 | BIND_ACTION_SEARCH_FIND_NEXT, 75 | BIND_ACTION_SEARCH_EDIT_LEFT, 76 | BIND_ACTION_SEARCH_EDIT_LEFT_WORD, 77 | BIND_ACTION_SEARCH_EDIT_RIGHT, 78 | BIND_ACTION_SEARCH_EDIT_RIGHT_WORD, 79 | BIND_ACTION_SEARCH_EDIT_HOME, 80 | BIND_ACTION_SEARCH_EDIT_END, 81 | BIND_ACTION_SEARCH_DELETE_PREV, 82 | BIND_ACTION_SEARCH_DELETE_PREV_WORD, 83 | BIND_ACTION_SEARCH_DELETE_NEXT, 84 | BIND_ACTION_SEARCH_DELETE_NEXT_WORD, 85 | BIND_ACTION_SEARCH_EXTEND_CHAR, 86 | BIND_ACTION_SEARCH_EXTEND_WORD, 87 | BIND_ACTION_SEARCH_EXTEND_WORD_WS, 88 | BIND_ACTION_SEARCH_EXTEND_LINE_DOWN, 89 | BIND_ACTION_SEARCH_EXTEND_BACKWARD_CHAR, 90 | BIND_ACTION_SEARCH_EXTEND_BACKWARD_WORD, 91 | BIND_ACTION_SEARCH_EXTEND_BACKWARD_WORD_WS, 92 | BIND_ACTION_SEARCH_EXTEND_LINE_UP, 93 | BIND_ACTION_SEARCH_CLIPBOARD_PASTE, 94 | BIND_ACTION_SEARCH_PRIMARY_PASTE, 95 | BIND_ACTION_SEARCH_UNICODE_INPUT, 96 | BIND_ACTION_SEARCH_COUNT, 97 | }; 98 | 99 | enum bind_action_url { 100 | BIND_ACTION_URL_NONE, 101 | BIND_ACTION_URL_CANCEL, 102 | BIND_ACTION_URL_TOGGLE_URL_ON_JUMP_LABEL, 103 | BIND_ACTION_URL_COUNT, 104 | }; 105 | 106 | typedef tll(xkb_keycode_t) xkb_keycode_list_t; 107 | 108 | struct key_binding { 109 | enum key_binding_type type; 110 | 111 | int action; /* enum bind_action_* */ 112 | xkb_mod_mask_t mods; 113 | 114 | union { 115 | struct { 116 | xkb_keysym_t sym; 117 | xkb_keycode_list_t key_codes; 118 | } k; 119 | 120 | struct { 121 | uint32_t button; 122 | int count; 123 | } m; 124 | }; 125 | 126 | const struct binding_aux *aux; 127 | }; 128 | typedef tll(struct key_binding) key_binding_list_t; 129 | 130 | struct terminal; 131 | struct seat; 132 | struct wayland; 133 | 134 | struct key_binding_set { 135 | key_binding_list_t key; 136 | key_binding_list_t search; 137 | key_binding_list_t url; 138 | key_binding_list_t mouse; 139 | xkb_mod_mask_t selection_overrides; 140 | }; 141 | 142 | struct key_binding_manager; 143 | 144 | struct key_binding_manager *key_binding_manager_new(void); 145 | void key_binding_manager_destroy(struct key_binding_manager *mgr); 146 | 147 | void key_binding_new_for_seat( 148 | struct key_binding_manager *mgr, const struct seat *seat); 149 | 150 | void key_binding_new_for_conf( 151 | struct key_binding_manager *mgr, const struct wayland *wayl, 152 | const struct config *conf); 153 | 154 | /* Returns the set of key bindings associated with this seat/conf pair */ 155 | struct key_binding_set *key_binding_for( 156 | struct key_binding_manager *mgr, const struct config *conf, 157 | const struct seat *seat); 158 | 159 | /* Remove all key bindings tied to the specified seat */ 160 | void key_binding_remove_seat( 161 | struct key_binding_manager *mgr, const struct seat *seat); 162 | 163 | void key_binding_unref( 164 | struct key_binding_manager *mgr, const struct config *conf); 165 | 166 | void key_binding_load_keymap( 167 | struct key_binding_manager *mgr, const struct seat *seat); 168 | void key_binding_unload_keymap( 169 | struct key_binding_manager *mgr, const struct seat *seat); 170 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "macros.h" 5 | 6 | enum log_colorize { LOG_COLORIZE_NEVER, LOG_COLORIZE_ALWAYS, LOG_COLORIZE_AUTO }; 7 | enum log_facility { LOG_FACILITY_USER, LOG_FACILITY_DAEMON }; 8 | 9 | enum log_class { 10 | LOG_CLASS_NONE, 11 | LOG_CLASS_ERROR, 12 | LOG_CLASS_WARNING, 13 | LOG_CLASS_INFO, 14 | LOG_CLASS_DEBUG, 15 | LOG_CLASS_COUNT, 16 | }; 17 | 18 | void log_init(enum log_colorize colorize, bool do_syslog, 19 | enum log_facility syslog_facility, enum log_class log_level); 20 | void log_deinit(void); 21 | 22 | void log_msg( 23 | enum log_class log_class, const char *module, 24 | const char *file, int lineno, 25 | const char *fmt, ...) PRINTF(5); 26 | 27 | void log_errno( 28 | enum log_class log_class, const char *module, 29 | const char *file, int lineno, 30 | const char *fmt, ...) PRINTF(5); 31 | 32 | void log_errno_provided( 33 | enum log_class log_class, const char *module, 34 | const char *file, int lineno, int _errno, 35 | const char *fmt, ...) PRINTF(6); 36 | 37 | void log_msg_va( 38 | enum log_class log_class, const char *module, 39 | const char *file, int lineno, const char *fmt, va_list va) VPRINTF(5); 40 | void log_errno_va( 41 | enum log_class log_class, const char *module, 42 | const char *file, int lineno, 43 | const char *fmt, va_list va) VPRINTF(5); 44 | void log_errno_provided_va( 45 | enum log_class log_class, const char *module, 46 | const char *file, int lineno, int _errno, 47 | const char *fmt, va_list va) VPRINTF(6); 48 | 49 | 50 | int log_level_from_string(const char *str); 51 | const char *log_level_string_hint(void); 52 | 53 | #define LOG_ERR(...) \ 54 | log_msg(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) 55 | #define LOG_ERRNO(...) \ 56 | log_errno(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) 57 | #define LOG_ERRNO_P(_errno, ...) \ 58 | log_errno_provided(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, \ 59 | _errno, __VA_ARGS__) 60 | #define LOG_WARN(...) \ 61 | log_msg(LOG_CLASS_WARNING, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) 62 | #define LOG_INFO(...) \ 63 | log_msg(LOG_CLASS_INFO, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) 64 | 65 | #if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG 66 | #define LOG_DBG(...) \ 67 | log_msg(LOG_CLASS_DEBUG, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) 68 | #else 69 | #define LOG_DBG(...) 70 | #endif 71 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('docs', type: 'feature', 2 | description: 'Build and install documentation (man pages, example foot.ini, readme, changelog, license etc).') 3 | 4 | option('themes', type: 'boolean', value: true, 5 | description: 'Install themes (predefined color schemes)') 6 | 7 | option('ime', type: 'boolean', value: true, 8 | description: 'IME (Input Method Editor) support') 9 | 10 | option('grapheme-clustering', type: 'feature', 11 | description: 'Enables grapheme clustering using libutf8proc. Requires fcft with harfbuzz support to be useful.') 12 | 13 | option('tests', type: 'boolean', value: true, description: 'Build tests') 14 | 15 | option('terminfo', type: 'feature', value: 'enabled', description: 'Build and install foot\'s terminfo files.') 16 | option('default-terminfo', type: 'string', value: 'foot', 17 | description: 'Default value of the "term" option in foot.ini.') 18 | option('terminfo-base-name', type: 'string', 19 | description: 'Base name of the generated terminfo files. Defaults to the value of the \'default-terminfo\' meson option') 20 | option('custom-terminfo-install-location', type: 'string', value: '', 21 | description: 'Path to foot\'s terminfo, relative to ${prefix}. If set, foot will set $TERMINFO to this value in the client process.') 22 | 23 | option('systemd-units-dir', type: 'string', value: '', 24 | description: 'Where to install the systemd service files (absolute path). Default: ${systemduserunitdir}') 25 | 26 | option('utmp-backend', type: 'combo', value: 'auto', choices: ['none', 'libutempter', 'ulog', 'auto'], 27 | description: 'Which utmp logging backend to use. This affects how (with what arguments) the utmp helper binary (see \'utmp-default-helper-path\')is called. Default: auto (linux=libutempter, freebsd=ulog, others=none)') 28 | option('utmp-default-helper-path', type: 'string', value: 'auto', 29 | description: 'Default path to the utmp helper binary. Default: auto-detect') 30 | -------------------------------------------------------------------------------- /misc.c: -------------------------------------------------------------------------------- 1 | #include "misc.h" 2 | #include "char32.h" 3 | 4 | bool 5 | isword(char32_t wc, bool spaces_only, const char32_t *delimiters) 6 | { 7 | if (spaces_only) 8 | return isc32graph(wc); 9 | 10 | if (c32chr(delimiters, wc) != NULL) 11 | return false; 12 | 13 | return isc32graph(wc); 14 | } 15 | 16 | void 17 | timespec_add(const struct timespec *a, const struct timespec *b, 18 | struct timespec *res) 19 | { 20 | const long one_sec_in_ns = 1000000000; 21 | 22 | res->tv_sec = a->tv_sec + b->tv_sec; 23 | res->tv_nsec = a->tv_nsec + b->tv_nsec; 24 | /* tv_nsec may be negative */ 25 | if (res->tv_nsec >= one_sec_in_ns) { 26 | res->tv_sec++; 27 | res->tv_nsec -= one_sec_in_ns; 28 | } 29 | } 30 | 31 | void 32 | timespec_sub(const struct timespec *a, const struct timespec *b, 33 | struct timespec *res) 34 | { 35 | const long one_sec_in_ns = 1000000000; 36 | 37 | res->tv_sec = a->tv_sec - b->tv_sec; 38 | res->tv_nsec = a->tv_nsec - b->tv_nsec; 39 | /* tv_nsec may be negative */ 40 | if (res->tv_nsec < 0) { 41 | res->tv_sec--; 42 | res->tv_nsec += one_sec_in_ns; 43 | } 44 | } 45 | 46 | bool 47 | is_valid_utf8(const char *value) 48 | { 49 | return value != NULL && 50 | mbsntoc32(NULL, value, strlen(value), 0) != (size_t)-1; 51 | } 52 | -------------------------------------------------------------------------------- /misc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | bool isword(char32_t wc, bool spaces_only, const char32_t *delimiters); 8 | 9 | void timespec_add(const struct timespec *a, const struct timespec *b, struct timespec *res); 10 | void timespec_sub(const struct timespec *a, const struct timespec *b, struct timespec *res); 11 | 12 | bool is_valid_utf8(const char *value); 13 | -------------------------------------------------------------------------------- /notify.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | struct terminal; 9 | 10 | enum notify_when { 11 | /* First, so that it can be left out of initializer and still be 12 | the default */ 13 | NOTIFY_ALWAYS, 14 | 15 | NOTIFY_UNFOCUSED, 16 | NOTIFY_INVISIBLE 17 | }; 18 | 19 | enum notify_urgency { 20 | /* First, so that it can be left out of initializer and still be 21 | the default */ 22 | NOTIFY_URGENCY_NORMAL, 23 | 24 | NOTIFY_URGENCY_LOW, 25 | NOTIFY_URGENCY_CRITICAL, 26 | }; 27 | 28 | struct notification { 29 | /* 30 | * Set by caller of notify_notify() 31 | */ 32 | char *id; /* Internal notification ID */ 33 | 34 | char *app_id; /* Custom app-id, overrides the terminal's app-id if set */ 35 | char *title; /* Required */ 36 | char *body; 37 | char *category; 38 | 39 | enum notify_when when; 40 | enum notify_urgency urgency; 41 | int32_t expire_time; 42 | 43 | tll(char *) actions; 44 | 45 | char *icon_cache_id; 46 | char *icon_symbolic_name; 47 | uint8_t *icon_data; 48 | size_t icon_data_sz; 49 | 50 | bool focus; /* Focus the foot window when notification is activated */ 51 | bool may_be_programatically_closed; /* OSC-99: notification may be programmatically closed by the client */ 52 | bool report_activated; /* OSC-99: report notification activation to client */ 53 | bool report_closed; /* OSC-99: report notification closed to client */ 54 | 55 | bool muted; /* Explicitly mute the notification */ 56 | char *sound_name; /* Should be set to NULL if muted == true */ 57 | 58 | /* 59 | * Used internally by notify 60 | */ 61 | 62 | uint32_t external_id; /* Daemon assigned notification ID */ 63 | bool activated; /* User 'activated' the notification */ 64 | uint32_t button_count; /* Number of buttons (custom actions) in notification */ 65 | uint32_t activated_button; /* User activated one of the custom actions */ 66 | char *xdg_token; /* XDG activation token, from daemon */ 67 | 68 | pid_t pid; /* Notifier command PID */ 69 | int stdout_fd; /* Notifier command's stdout */ 70 | 71 | char *stdout_data; /* Data we've reado from command's stdout */ 72 | size_t stdout_sz; 73 | 74 | /* Used when notification provides raw icon data, and it's 75 | bypassing the icon cache */ 76 | char *icon_path; 77 | int icon_fd; 78 | }; 79 | 80 | struct notification_icon { 81 | char *id; 82 | char *symbolic_name; 83 | char *tmp_file_name; 84 | int tmp_file_fd; 85 | }; 86 | 87 | bool notify_notify(struct terminal *term, struct notification *notif); 88 | void notify_close(struct terminal *term, const char *id); 89 | void notify_free(struct terminal *term, struct notification *notif); 90 | 91 | void notify_icon_add(struct terminal *term, const char *id, 92 | const char *symbolic_name, const uint8_t *data, 93 | size_t data_sz); 94 | void notify_icon_del(struct terminal *term, const char *id); 95 | void notify_icon_free(struct notification_icon *icon); 96 | -------------------------------------------------------------------------------- /org.codeberg.dnkl.foot.metainfo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.codeberg.dnkl.foot 4 | MIT 5 | MIT 6 | dnkl 7 | foot 8 | The fast, lightweight and minimalistic Wayland terminal emulator. 9 | 10 |
    11 |
  • Fast
  • 12 |
  • Lightweight, in dependencies, on-disk and in-memory
  • 13 |
  • Wayland native
  • 14 |
  • DE agnostic
  • 15 |
  • Server/daemon mode
  • 16 |
  • User configurable font fallback
  • 17 |
  • On-the-fly font resize
  • 18 |
  • On-the-fly DPI font size adjustment
  • 19 |
  • Scrollback search
  • 20 |
  • Keyboard driven URL detection
  • 21 |
  • Color emoji support
  • 22 |
  • IME (via text-input-v3)
  • 23 |
  • Multi-seat
  • 24 |
  • True Color (24bpp)
  • 25 |
  • Styled and colored underlines
  • 26 |
  • Synchronized Updates support
  • 27 |
  • Sixel image support
  • 28 |
29 |
30 | 31 | 32 | Foot with sixel graphics 33 | https://codeberg.org/dnkl/foot/media/branch/master/doc/sixel-wow.png 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.codeberg.dnkl.foot.desktop 54 | https://codeberg.org/dnkl/foot 55 | https://codeberg.org/dnkl/foot/issues 56 | 57 |
58 | -------------------------------------------------------------------------------- /osc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "terminal.h" 5 | 6 | bool osc_ensure_size(struct terminal *term, size_t required_size); 7 | void osc_dispatch(struct terminal *term); 8 | -------------------------------------------------------------------------------- /pgo/full-current-session.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eux 4 | 5 | srcdir=$(realpath "${1}") 6 | blddir=$(realpath "${2}") 7 | 8 | "${srcdir}"/pgo/full-inner.sh "${srcdir}" "${blddir}" 9 | -------------------------------------------------------------------------------- /pgo/full-headless-cage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eux 4 | 5 | srcdir=$(realpath "${1}") 6 | blddir=$(realpath "${2}") 7 | 8 | runtime_dir=$(mktemp -d) 9 | trap "rm -rf '${runtime_dir}'" EXIT INT HUP TERM 10 | 11 | XDG_RUNTIME_DIR="${runtime_dir}" WLR_RENDERER=pixman WLR_BACKENDS=headless cage "${srcdir}"/pgo/full-inner.sh "${srcdir}" "${blddir}" 12 | 13 | # Cage's exit code doesn't reflect our script's exit code 14 | [ -f "${blddir}"/pgo-ok ] || exit 1 15 | -------------------------------------------------------------------------------- /pgo/full-headless-sway-inner.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ux 4 | 5 | srcdir=$(realpath "${1}") 6 | blddir=$(realpath "${2}") 7 | 8 | "${srcdir}"/pgo/full-inner.sh "${srcdir}" "${blddir}" 9 | swaymsg exit 10 | -------------------------------------------------------------------------------- /pgo/full-headless-sway.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eux 4 | 5 | srcdir=$(realpath "${1}") 6 | blddir=$(realpath "${2}") 7 | 8 | runtime_dir=$(mktemp -d) 9 | sway_conf=$(mktemp) 10 | 11 | cleanup() { 12 | rm -f "${sway_conf}" 13 | rm -rf "${runtime_dir}" 14 | } 15 | trap cleanup EXIT INT HUP TERM 16 | 17 | # Generate a custom config that executes our generate-pgo-data script 18 | > "${sway_conf}" echo "exec '${srcdir}'/pgo/full-headless-sway-inner.sh '${srcdir}' '${blddir}'" 19 | 20 | # Run Sway. full-headless-sway-inner.sh ends with a 'swaymsg exit' 21 | XDG_RUNTIME_DIR="${runtime_dir}" WLR_RENDERER=pixman WLR_BACKENDS=headless sway -c "${sway_conf}" 22 | 23 | # Sway's exit code doesn't reflect our script's exit code 24 | [ -f "${blddir}"/pgo-ok ] || exit 1 25 | -------------------------------------------------------------------------------- /pgo/full-inner.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eux 4 | 5 | srcdir=$(realpath "${1}") 6 | blddir=$(realpath "${2}") 7 | 8 | . "${srcdir}"/pgo/options 9 | 10 | pgo_data=$(mktemp) 11 | trap "rm -f '${pgo_data}'" EXIT INT HUP TERM 12 | 13 | rm -f "${blddir}"/pgo-ok 14 | 15 | # To ensure profiling data is generated in the build directory 16 | cd "${blddir}" 17 | 18 | "${blddir}"/utils/xtgettcap 19 | "${blddir}"/footclient --version 20 | "${blddir}"/foot \ 21 | --config=/dev/null \ 22 | --override tweak.grapheme-shaping=no \ 23 | --term=xterm \ 24 | sh -c " 25 | set -eux 26 | 27 | '${srcdir}/scripts/generate-alt-random-writes.py' \ 28 | ${script_options} \"${pgo_data}\" 29 | 30 | cat \"${pgo_data}\" 31 | " 32 | touch "${blddir}"/pgo-ok 33 | -------------------------------------------------------------------------------- /pgo/options: -------------------------------------------------------------------------------- 1 | script_options="--scroll --scroll-region --colors-regular --colors-bright --colors-256 --colors-rgb --attr-bold --attr-italic --attr-underline --sixel" 2 | -------------------------------------------------------------------------------- /pgo/partial.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eux 4 | 5 | srcdir=$(realpath "${1}") 6 | blddir=$(realpath "${2}") 7 | 8 | . "${srcdir}"/pgo/options 9 | 10 | pgo_data=$(mktemp) 11 | trap "rm -f ${pgo_data}" EXIT INT HUP TERM 12 | 13 | rm -f "${blddir}"/pgo-ok 14 | 15 | "${srcdir}"/scripts/generate-alt-random-writes.py \ 16 | --rows=67 \ 17 | --cols=135 \ 18 | ${script_options} \ 19 | "${pgo_data}" 20 | 21 | # To ensure profiling data is generated in the build directory 22 | cd "${blddir}" 23 | 24 | "${blddir}"/utils/xtgettcap 25 | "${blddir}"/footclient --version 26 | "${blddir}"/foot --version 27 | "${blddir}"/pgo "${pgo_data}" 28 | 29 | touch "${blddir}"/pgo-ok 30 | -------------------------------------------------------------------------------- /pgo/pgo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | usage_and_die() { 6 | echo "Usage: ${0} none|partial|full-current-session|full-headless-sway|full-headless-cage|[auto] [meson options]" 7 | exit 1 8 | } 9 | 10 | [ ${#} -ge 3 ] || usage_and_die 11 | 12 | mode=${1} 13 | srcdir=$(realpath "${2}") 14 | blddir=$(realpath "${3}") 15 | shift 3 16 | 17 | # if [ -e "${blddir}" ]; then 18 | # echo "error: ${blddir}: build directory already exists" 19 | # exit 1 20 | # fi 21 | 22 | if [ ! -f "${srcdir}"/generate-version.sh ]; then 23 | echo "error: ${srcdir}: does not appear to be a foot source directory" 24 | exit 1 25 | fi 26 | 27 | compiler=other 28 | do_pgo=no 29 | 30 | CFLAGS="${CFLAGS-} -O3" 31 | 32 | case $(${CC-cc} --version) in 33 | *Free\ Software\ Foundation*) 34 | compiler=gcc 35 | do_pgo=yes 36 | ;; 37 | 38 | *clang*) 39 | compiler=clang 40 | 41 | if command -v llvm-profdata > /dev/null; then 42 | do_pgo=yes 43 | CFLAGS="${CFLAGS} -Wno-ignored-optimization-argument" 44 | fi 45 | ;; 46 | esac 47 | 48 | case ${mode} in 49 | partial|full-current-session|full-headless-sway|full-headless-cage) 50 | ;; 51 | 52 | none) 53 | do_pgo=no 54 | ;; 55 | 56 | auto) 57 | # TODO: once Sway 1.6.2 has been released, prefer 58 | # full-headless-sway 59 | 60 | if [ -n "${WAYLAND_DISPLAY+x}" ]; then 61 | mode=full-current-session 62 | # elif command -v sway > /dev/null; then # Requires 1.6.2 63 | # mode=full-headless-sway 64 | elif command -v cage > /dev/null; then 65 | mode=full-headless-cage 66 | else 67 | mode=partial 68 | fi 69 | ;; 70 | 71 | *) 72 | usage_and_die 73 | ;; 74 | esac 75 | 76 | set -x 77 | 78 | # echo "source: ${srcdir}" 79 | # echo "build: ${blddir}" 80 | # echo "compiler: ${compiler}" 81 | # echo "mode: ${mode}" 82 | # echo "CFLAGS: ${CFLAGS}" 83 | 84 | export CFLAGS 85 | export CCACHE_DISABLE=1 86 | meson setup --buildtype=release -Db_lto=true "${@}" "${blddir}" "${srcdir}" 87 | 88 | if [ ${do_pgo} = yes ]; then 89 | find "${blddir}" \ 90 | '(' \ 91 | -name "*.gcda" -o \ 92 | -name "*.profraw" -o \ 93 | -name default.profdata \ 94 | ')' \ 95 | -delete 96 | 97 | meson configure "${blddir}" -Db_pgo=generate 98 | ninja -C "${blddir}" 99 | 100 | # If fcft/tllist are subprojects, we need to ensure their tests 101 | # have been executed, or we'll get "profile count data file not 102 | # found" errors. 103 | ninja -C "${blddir}" test 104 | 105 | # Run mode-dependent script to generate profiling data 106 | "${srcdir}"/pgo/${mode}.sh "${srcdir}" "${blddir}" 107 | 108 | if [ ${compiler} = clang ]; then 109 | llvm-profdata \ 110 | merge \ 111 | "${blddir}"/default_*.profraw \ 112 | --output="${blddir}"/default.profdata 113 | fi 114 | 115 | meson configure "${blddir}" -Db_pgo=use 116 | fi 117 | 118 | ninja -C "${blddir}" 119 | -------------------------------------------------------------------------------- /quirks.c: -------------------------------------------------------------------------------- 1 | #include "quirks.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define LOG_MODULE "quirks" 8 | #define LOG_ENABLE_DBG 0 9 | #include "log.h" 10 | #include "util.h" 11 | 12 | static bool 13 | is_weston(void) 14 | { 15 | static bool is_weston = false; 16 | static bool initialized = false; 17 | 18 | if (!initialized) { 19 | initialized = true; 20 | is_weston = getenv("WESTON_CONFIG_FILE") != NULL; 21 | if (is_weston) 22 | LOG_WARN("applying wl_subsurface_set_desync() workaround for weston"); 23 | } 24 | 25 | return is_weston; 26 | } 27 | 28 | void 29 | quirk_weston_subsurface_desync_on(struct wl_subsurface *sub) 30 | { 31 | if (!is_weston()) 32 | return; 33 | 34 | wl_subsurface_set_desync(sub); 35 | } 36 | 37 | void 38 | quirk_weston_subsurface_desync_off(struct wl_subsurface *sub) 39 | { 40 | if (!is_weston()) 41 | return; 42 | 43 | wl_subsurface_set_sync(sub); 44 | } 45 | 46 | void 47 | quirk_weston_csd_on(struct terminal *term) 48 | { 49 | if (term->window->csd_mode != CSD_YES) 50 | return; 51 | if (term->window->is_fullscreen) 52 | return; 53 | 54 | for (int i = 0; i < ALEN(term->window->csd.surface); i++) 55 | quirk_weston_subsurface_desync_on(term->window->csd.surface[i].sub); 56 | } 57 | 58 | void 59 | quirk_weston_csd_off(struct terminal *term) 60 | { 61 | if (term->window->csd_mode != CSD_YES) 62 | return; 63 | if (term->window->is_fullscreen) 64 | return; 65 | 66 | for (int i = 0; i < ALEN(term->window->csd.surface); i++) 67 | quirk_weston_subsurface_desync_off(term->window->csd.surface[i].sub); 68 | } 69 | 70 | static bool 71 | is_sway(void) 72 | { 73 | static bool is_sway = false; 74 | static bool initialized = false; 75 | 76 | if (!initialized) { 77 | initialized = true; 78 | is_sway = getenv("SWAYSOCK") != NULL; 79 | if (is_sway) 80 | LOG_WARN("applying wl_surface_damage_buffer() workaround for Sway"); 81 | } 82 | 83 | return is_sway; 84 | } 85 | 86 | void 87 | quirk_sway_subsurface_unmap(struct terminal *term) 88 | { 89 | if (!is_sway()) 90 | return; 91 | 92 | wl_surface_damage_buffer(term->window->surface.surf, 0, 0, INT32_MAX, INT32_MAX); 93 | } 94 | -------------------------------------------------------------------------------- /quirks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "terminal.h" 6 | 7 | /* 8 | * On weston (8.0), synchronized subsurfaces aren't updated correctly. 9 | 10 | * They appear to render once, but after that, updates are 11 | * sporadic. Sometimes they update, most of the time they don't. 12 | * 13 | * Adding explicit parent surface commits right after the subsurface 14 | * commit doesn't help (and would be useless anyway, since it would 15 | * defeat the purpose of having the subsurface synchronized in the 16 | * first place). 17 | */ 18 | void quirk_weston_subsurface_desync_on(struct wl_subsurface *sub); 19 | void quirk_weston_subsurface_desync_off(struct wl_subsurface *sub); 20 | 21 | /* Shortcuts to call desync_{on,off} on all CSD subsurfaces */ 22 | void quirk_weston_csd_on(struct terminal *term); 23 | void quirk_weston_csd_off(struct terminal *term); 24 | 25 | void quirk_sway_subsurface_unmap(struct terminal *term); 26 | -------------------------------------------------------------------------------- /reaper.c: -------------------------------------------------------------------------------- 1 | #include "reaper.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define LOG_MODULE "reaper" 11 | #define LOG_ENABLE_DBG 0 12 | #include "log.h" 13 | 14 | struct child { 15 | pid_t pid; 16 | reaper_cb cb; 17 | void *cb_data; 18 | }; 19 | 20 | struct reaper { 21 | struct fdm *fdm; 22 | tll(struct child) children; 23 | }; 24 | 25 | static bool fdm_reap(struct fdm *fdm, int signo, void *data); 26 | 27 | struct reaper * 28 | reaper_init(struct fdm *fdm) 29 | { 30 | struct reaper *reaper = malloc(sizeof(*reaper)); 31 | if (unlikely(reaper == NULL)) { 32 | LOG_ERRNO("malloc() failed"); 33 | return NULL; 34 | } 35 | 36 | *reaper = (struct reaper){ 37 | .fdm = fdm, 38 | .children = tll_init(), 39 | }; 40 | 41 | if (!fdm_signal_add(fdm, SIGCHLD, &fdm_reap, reaper)) 42 | goto err; 43 | 44 | return reaper; 45 | 46 | err: 47 | tll_free(reaper->children); 48 | free(reaper); 49 | return NULL; 50 | } 51 | 52 | void 53 | reaper_destroy(struct reaper *reaper) 54 | { 55 | if (reaper == NULL) 56 | return; 57 | 58 | fdm_signal_del(reaper->fdm, SIGCHLD); 59 | tll_free(reaper->children); 60 | free(reaper); 61 | } 62 | 63 | void 64 | reaper_add(struct reaper *reaper, pid_t pid, reaper_cb cb, void *cb_data) 65 | { 66 | LOG_DBG("adding pid=%d", pid); 67 | tll_push_back( 68 | reaper->children, 69 | ((struct child){.pid = pid, .cb = cb, .cb_data = cb_data})); 70 | } 71 | 72 | void 73 | reaper_del(struct reaper *reaper, pid_t pid) 74 | { 75 | tll_foreach(reaper->children, it) { 76 | if (it->item.pid == pid) { 77 | tll_remove(reaper->children, it); 78 | break; 79 | } 80 | } 81 | } 82 | 83 | static bool 84 | fdm_reap(struct fdm *fdm, int signo, void *data) 85 | { 86 | struct reaper *reaper = data; 87 | 88 | while (true) { 89 | int status; 90 | pid_t pid = waitpid(-1, &status, WNOHANG); 91 | if (pid <= 0) 92 | break; 93 | 94 | if (WIFEXITED(status)) 95 | LOG_DBG("pid=%d: exited with status=%d", pid, WEXITSTATUS(status)); 96 | else if (WIFSIGNALED(status)) 97 | LOG_DBG("pid=%d: killed by signal=%d", pid, WTERMSIG(status)); 98 | else 99 | LOG_DBG("pid=%d: died of unknown resason", pid); 100 | 101 | tll_foreach(reaper->children, it) { 102 | struct child *_child = &it->item; 103 | 104 | if (_child->pid != pid) 105 | continue; 106 | 107 | /* Make sure we remove it *before* the callback, since it too 108 | * may remove it */ 109 | struct child child = it->item; 110 | tll_remove(reaper->children, it); 111 | 112 | if (child.cb != NULL) 113 | child.cb(reaper, child.pid, status, child.cb_data); 114 | 115 | break; 116 | } 117 | } 118 | 119 | return true; 120 | } 121 | -------------------------------------------------------------------------------- /reaper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "fdm.h" 7 | 8 | struct reaper; 9 | 10 | struct reaper *reaper_init(struct fdm *fdm); 11 | void reaper_destroy(struct reaper *reaper); 12 | 13 | typedef void (*reaper_cb)( 14 | struct reaper *reaper, pid_t pid, int status, void *data); 15 | 16 | void reaper_add(struct reaper *reaper, pid_t pid, reaper_cb cb, void *cb_data); 17 | void reaper_del(struct reaper *reaper, pid_t pid); 18 | -------------------------------------------------------------------------------- /render.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "terminal.h" 5 | #include "fdm.h" 6 | #include "wayland.h" 7 | #include "misc.h" 8 | 9 | struct renderer; 10 | struct renderer *render_init(struct fdm *fdm, struct wayland *wayl); 11 | void render_destroy(struct renderer *renderer); 12 | 13 | enum resize_options { 14 | RESIZE_NORMAL = 0, 15 | RESIZE_FORCE = 1 << 0, 16 | RESIZE_BY_CELLS = 1 << 1, 17 | RESIZE_KEEP_GRID = 1 << 2, 18 | }; 19 | 20 | bool render_resize( 21 | struct terminal *term, int width, int height, uint8_t resize_options); 22 | 23 | void render_refresh(struct terminal *term); 24 | void render_refresh_app_id(struct terminal *term); 25 | void render_refresh_icon(struct terminal *term); 26 | void render_refresh_csd(struct terminal *term); 27 | void render_refresh_search(struct terminal *term); 28 | void render_refresh_title(struct terminal *term); 29 | void render_refresh_urls(struct terminal *term); 30 | bool render_xcursor_set( 31 | struct seat *seat, struct terminal *term, enum cursor_shape shape); 32 | bool render_xcursor_is_valid(const struct seat *seat, const char *cursor); 33 | 34 | struct render_worker_context { 35 | int my_id; 36 | struct terminal *term; 37 | }; 38 | int render_worker_thread(void *_ctx); 39 | 40 | struct csd_data { 41 | int x; 42 | int y; 43 | int width; 44 | int height; 45 | }; 46 | 47 | struct csd_data get_csd_data(const struct terminal *term, enum csd_surface surf_idx); 48 | -------------------------------------------------------------------------------- /scripts/benchmark.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S python3 -u 2 | 3 | import argparse 4 | import fcntl 5 | import os 6 | import statistics 7 | import struct 8 | import sys 9 | import termios 10 | 11 | from datetime import datetime 12 | 13 | 14 | def main(): 15 | parser = argparse.ArgumentParser() 16 | parser.add_argument('files', type=argparse.FileType('rb'), nargs='+') 17 | parser.add_argument('--iterations', type=int, default=20) 18 | 19 | args = parser.parse_args() 20 | 21 | lines, cols, height, width = struct.unpack( 22 | 'HHHH', 23 | fcntl.ioctl(sys.stdout.fileno(), 24 | termios.TIOCGWINSZ, 25 | struct.pack('HHHH', 0, 0, 0, 0))) 26 | 27 | times = {name: [] for name in [f.name for f in args.files]} 28 | 29 | for f in args.files: 30 | bench_bytes = f.read() 31 | 32 | for i in range(args.iterations): 33 | start = datetime.now() 34 | sys.stdout.buffer.write(bench_bytes) 35 | stop = datetime.now() 36 | 37 | times[f.name].append((stop - start).total_seconds()) 38 | 39 | del bench_bytes 40 | 41 | print('\033[J') 42 | print(times) 43 | print(f'cols={cols}, lines={lines}, width={width}px, height={height}px') 44 | for f in args.files: 45 | print(f'{os.path.basename(f.name)}: ' 46 | f'{statistics.mean(times[f.name]):.3f}s ' 47 | f'±{statistics.stdev(times[f.name]):.3f}') 48 | 49 | 50 | if __name__ == '__main__': 51 | sys.exit(main()) 52 | -------------------------------------------------------------------------------- /scripts/generate-emoji-variation-sequences.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import sys 5 | 6 | 7 | class Codepoint: 8 | def __init__(self, start: int, end: None|int = None): 9 | self.start = start 10 | self.end = start if end is None else end 11 | self.vs15 = False 12 | self.vs16 = False 13 | 14 | def __repr__(self) -> str: 15 | return f'{self.start:x}-{self.end:x}, vs15={self.vs15}, vs16={self.vs16}' 16 | 17 | 18 | def main(): 19 | parser = argparse.ArgumentParser() 20 | parser.add_argument('input', type=argparse.FileType('r')) 21 | parser.add_argument('output', type=argparse.FileType('w')) 22 | opts = parser.parse_args() 23 | 24 | codepoints: dict[int, Codepoint] = {} 25 | 26 | for line in opts.input: 27 | line = line.rstrip() 28 | if not line: 29 | continue 30 | if line[0] == '#': 31 | continue 32 | 33 | # Example: "0023 FE0E ; text style; # (1.1) NUMBER SIGN" 34 | cps, _ = line.split(';', maxsplit=1) # cps = "0023 FE0F " 35 | cps = cps.strip().split(' ') # cps = ["0023", "FE0F"] 36 | 37 | if len(cps) != 2: 38 | raise NotImplementedError(f'emoji variation sequences with more than one base codepoint: {cps}') 39 | 40 | cp, vs = cps # cp = "0023", vs = "FE0F" 41 | cp = int(cp, 16) # cp = 0x23 42 | vs = int(vs, 16) # vs = 0xfe0f 43 | 44 | assert vs in [0xfe0e, 0xfe0f] 45 | 46 | if cp not in codepoints: 47 | codepoints[cp] = Codepoint(cp) 48 | 49 | assert codepoints[cp].start == cp 50 | 51 | if vs == 0xfe0e: 52 | codepoints[cp].vs15 = True 53 | else: 54 | codepoints[cp].vs16 = True 55 | 56 | sorted_list = sorted(codepoints.values(), key=lambda cp: cp.start) 57 | 58 | compacted: list[Codepoint] = [] 59 | for i, cp in enumerate(sorted_list): 60 | assert cp.end == cp.start 61 | 62 | if i == 0: 63 | compacted.append(cp) 64 | continue 65 | 66 | last_cp = compacted[-1] 67 | if last_cp.end == cp.start - 1 and last_cp.vs15 == cp.vs15 and last_cp.vs16 == cp.vs16: 68 | compacted[-1].end = cp.start 69 | else: 70 | compacted.append(cp) 71 | 72 | opts.output.write('#pragma once\n') 73 | opts.output.write('#include \n') 74 | opts.output.write('#include \n') 75 | opts.output.write('\n') 76 | opts.output.write('struct emoji_vs {\n') 77 | opts.output.write(' uint32_t start:21;\n') 78 | opts.output.write(' uint32_t end:21;\n') 79 | opts.output.write(' bool vs15:1;\n') 80 | opts.output.write(' bool vs16:1;\n') 81 | opts.output.write('} __attribute__((packed));\n') 82 | opts.output.write('_Static_assert(sizeof(struct emoji_vs) == 6, "unexpected struct size");\n') 83 | opts.output.write('\n') 84 | opts.output.write('#if defined(FOOT_GRAPHEME_CLUSTERING)\n') 85 | opts.output.write('\n') 86 | 87 | opts.output.write(f'static const struct emoji_vs emoji_vs[{len(compacted)}] = {{\n') 88 | 89 | for cp in compacted: 90 | opts.output.write(' {\n') 91 | opts.output.write(f' .start = 0x{cp.start:X},\n') 92 | opts.output.write(f' .end = 0x{cp.end:x},\n') 93 | opts.output.write(f' .vs15 = {"true" if cp.vs15 else "false"},\n') 94 | opts.output.write(f' .vs16 = {"true" if cp.vs16 else "false"},\n') 95 | opts.output.write(' },\n') 96 | 97 | opts.output.write('};\n') 98 | opts.output.write('\n') 99 | opts.output.write('#endif /* FOOT_GRAPHEME_CLUSTERING */\n') 100 | 101 | 102 | if __name__ == '__main__': 103 | sys.exit(main()) 104 | -------------------------------------------------------------------------------- /search.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "key-binding.h" 6 | #include "terminal.h" 7 | 8 | void search_begin(struct terminal *term); 9 | void search_cancel(struct terminal *term); 10 | void search_input( 11 | struct seat *seat, struct terminal *term, 12 | const struct key_binding_set *bindings, uint32_t key, 13 | xkb_keysym_t sym, xkb_mod_mask_t mods, xkb_mod_mask_t consumed, 14 | const xkb_keysym_t *raw_syms, size_t raw_count, 15 | uint32_t serial); 16 | void search_add_chars(struct terminal *term, const char *text, size_t len); 17 | 18 | void search_selection_cancelled(struct terminal *term); 19 | 20 | struct search_match_iterator { 21 | struct terminal *term; 22 | struct coord start; 23 | }; 24 | 25 | struct search_match_iterator search_matches_new_iter(struct terminal *term); 26 | struct range search_matches_next(struct search_match_iterator *iter); 27 | -------------------------------------------------------------------------------- /selection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "terminal.h" 7 | 8 | extern const struct wl_data_device_listener data_device_listener; 9 | extern const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener; 10 | 11 | void selection_start( 12 | struct terminal *term, int col, int row, 13 | enum selection_kind new_kind, bool spaces_only); 14 | void selection_update(struct terminal *term, int col, int row); 15 | void selection_finalize( 16 | struct seat *seat, struct terminal *term, uint32_t serial); 17 | void selection_dirty_cells(struct terminal *term); 18 | void selection_cancel(struct terminal *term); 19 | void selection_extend( 20 | struct seat *seat, struct terminal *term, 21 | int col, int row, enum selection_kind kind); 22 | 23 | bool selection_on_rows(const struct terminal *term, int start, int end); 24 | 25 | void selection_scroll_up(struct terminal *term, int rows); 26 | void selection_scroll_down(struct terminal *term, int rows); 27 | void selection_view_up(struct terminal *term, int new_view); 28 | void selection_view_down(struct terminal *term, int new_view); 29 | 30 | void selection_clipboard_unset(struct seat *seat); 31 | void selection_primary_unset(struct seat *seat); 32 | 33 | bool selection_clipboard_has_data(const struct seat *seat); 34 | bool selection_primary_has_data(const struct seat *seat); 35 | 36 | char *selection_to_text(const struct terminal *term); 37 | void selection_to_clipboard( 38 | struct seat *seat, struct terminal *term, uint32_t serial); 39 | void selection_from_clipboard( 40 | struct seat *seat, struct terminal *term, uint32_t serial); 41 | void selection_to_primary( 42 | struct seat *seat, struct terminal *term, uint32_t serial); 43 | void selection_from_primary(struct seat *seat, struct terminal *term); 44 | 45 | /* Copy text *to* primary/clipboard */ 46 | bool text_to_clipboard( 47 | struct seat *seat, struct terminal *term, char *text, uint32_t serial); 48 | bool text_to_primary( 49 | struct seat *seat, struct terminal *term, char *text, uint32_t serial); 50 | 51 | /* 52 | * Copy text *from* primary/clipboard 53 | * 54 | * Note that these are asynchronous; they *will* return 55 | * immediately. The 'cb' callback will be called 0..n times with 56 | * clipboard data. When done (or on error), the 'done' callback is 57 | * called. 58 | * 59 | * As such, keep this in mind: 60 | * - The 'user' context must not be stack allocated 61 | * - Don't expect clipboard data to have been received when these 62 | * functions return (it will *never* have been received at this 63 | * point). 64 | */ 65 | void text_from_clipboard( 66 | struct seat *seat, struct terminal *term, 67 | void (*cb)(char *data, size_t size, void *user), 68 | void (*done)(void *user), void *user); 69 | 70 | void text_from_primary( 71 | struct seat *seat, struct terminal *term, 72 | void (*cb)(char *data, size_t size, void *user), 73 | void (*dont)(void *user), void *user); 74 | 75 | void selection_start_scroll_timer( 76 | struct terminal *term, int interval_ns, 77 | enum selection_scroll_direction direction, int col); 78 | void selection_stop_scroll_timer(struct terminal *term); 79 | 80 | void selection_find_word_boundary_left( 81 | const struct terminal *term, struct coord *pos, bool spaces_only); 82 | void selection_find_word_boundary_right( 83 | const struct terminal *term, struct coord *pos, bool spaces_only, 84 | bool stop_on_space_to_word_boundary); 85 | 86 | struct coord selection_get_start(const struct terminal *term); 87 | struct coord selection_get_end(const struct terminal *term); 88 | -------------------------------------------------------------------------------- /server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fdm.h" 4 | #include "config.h" 5 | #include "reaper.h" 6 | #include "wayland.h" 7 | 8 | struct server; 9 | struct server *server_init(const struct config *conf, struct fdm *fdm, 10 | struct reaper *reaper, struct wayland *wayl); 11 | void server_destroy(struct server *server); 12 | -------------------------------------------------------------------------------- /shm-formats.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #if defined(_DEBUG) 6 | static const struct shm_formats { 7 | uint32_t format; 8 | const char *description; 9 | } shm_formats[] = { 10 | {WL_SHM_FORMAT_ARGB8888, "ARGB8888"}, 11 | {WL_SHM_FORMAT_XRGB8888, "XRGB8888"}, 12 | {WL_SHM_FORMAT_C8, "C8"}, 13 | {WL_SHM_FORMAT_RGB332, "RGB332"}, 14 | {WL_SHM_FORMAT_BGR233, "BGR233"}, 15 | {WL_SHM_FORMAT_XRGB4444, "XRGB4444"}, 16 | {WL_SHM_FORMAT_XBGR4444, "XBGR4444"}, 17 | {WL_SHM_FORMAT_RGBX4444, "RGBX4444"}, 18 | {WL_SHM_FORMAT_BGRX4444, "BGRX4444"}, 19 | {WL_SHM_FORMAT_ARGB4444, "ARGB4444"}, 20 | {WL_SHM_FORMAT_ABGR4444, "ABGR4444"}, 21 | {WL_SHM_FORMAT_RGBA4444, "RGBA4444"}, 22 | {WL_SHM_FORMAT_BGRA4444, "BGRA4444"}, 23 | {WL_SHM_FORMAT_XRGB1555, "XRGB1555"}, 24 | {WL_SHM_FORMAT_XBGR1555, "XBGR1555"}, 25 | {WL_SHM_FORMAT_RGBX5551, "RGBX5551"}, 26 | {WL_SHM_FORMAT_BGRX5551, "BGRX5551"}, 27 | {WL_SHM_FORMAT_ARGB1555, "ARGB1555"}, 28 | {WL_SHM_FORMAT_ABGR1555, "ABGR1555"}, 29 | {WL_SHM_FORMAT_RGBA5551, "RGBA5551"}, 30 | {WL_SHM_FORMAT_BGRA5551, "BGRA5551"}, 31 | {WL_SHM_FORMAT_RGB565, "RGB565"}, 32 | {WL_SHM_FORMAT_BGR565, "BGR565"}, 33 | {WL_SHM_FORMAT_RGB888, "RGB888"}, 34 | {WL_SHM_FORMAT_BGR888, "BGR888"}, 35 | {WL_SHM_FORMAT_XBGR8888, "XBGR8888"}, 36 | {WL_SHM_FORMAT_RGBX8888, "RGBX8888"}, 37 | {WL_SHM_FORMAT_BGRX8888, "BGRX8888"}, 38 | {WL_SHM_FORMAT_ABGR8888, "ABGR8888"}, 39 | {WL_SHM_FORMAT_RGBA8888, "RGBA8888"}, 40 | {WL_SHM_FORMAT_BGRA8888, "BGRA8888"}, 41 | {WL_SHM_FORMAT_XRGB2101010, "XRGB2101010"}, 42 | {WL_SHM_FORMAT_XBGR2101010, "XBGR2101010"}, 43 | {WL_SHM_FORMAT_RGBX1010102, "RGBX1010102"}, 44 | {WL_SHM_FORMAT_BGRX1010102, "BGRX1010102"}, 45 | {WL_SHM_FORMAT_ARGB2101010, "ARGB2101010"}, 46 | {WL_SHM_FORMAT_ABGR2101010, "ABGR2101010"}, 47 | {WL_SHM_FORMAT_RGBA1010102, "RGBA1010102"}, 48 | {WL_SHM_FORMAT_BGRA1010102, "BGRA1010102"}, 49 | {WL_SHM_FORMAT_YUYV, "YUYV"}, 50 | {WL_SHM_FORMAT_YVYU, "YVYU"}, 51 | {WL_SHM_FORMAT_UYVY, "UYVY"}, 52 | {WL_SHM_FORMAT_VYUY, "VYUY"}, 53 | {WL_SHM_FORMAT_AYUV, "AYUV"}, 54 | {WL_SHM_FORMAT_NV12, "NV12"}, 55 | {WL_SHM_FORMAT_NV21, "NV21"}, 56 | {WL_SHM_FORMAT_NV16, "NV16"}, 57 | {WL_SHM_FORMAT_NV61, "NV61"}, 58 | {WL_SHM_FORMAT_YUV410, "YUV410"}, 59 | {WL_SHM_FORMAT_YVU410, "YVU410"}, 60 | {WL_SHM_FORMAT_YUV411, "YUV411"}, 61 | {WL_SHM_FORMAT_YVU411, "YVU411"}, 62 | {WL_SHM_FORMAT_YUV420, "YUV420"}, 63 | {WL_SHM_FORMAT_YVU420, "YVU420"}, 64 | {WL_SHM_FORMAT_YUV422, "YUV422"}, 65 | {WL_SHM_FORMAT_YVU422, "YVU422"}, 66 | {WL_SHM_FORMAT_YUV444, "YUV444"}, 67 | {WL_SHM_FORMAT_YVU444, "YVU444"}, 68 | {WL_SHM_FORMAT_R8, "R8"}, 69 | {WL_SHM_FORMAT_R16, "R16"}, 70 | {WL_SHM_FORMAT_RG88, "RG88"}, 71 | {WL_SHM_FORMAT_GR88, "GR88"}, 72 | {WL_SHM_FORMAT_RG1616, "RG1616"}, 73 | {WL_SHM_FORMAT_GR1616, "GR1616"}, 74 | {WL_SHM_FORMAT_XRGB16161616F, "XRGB16161616F"}, 75 | {WL_SHM_FORMAT_XBGR16161616F, "XBGR16161616F"}, 76 | {WL_SHM_FORMAT_ARGB16161616F, "ARGB16161616F"}, 77 | {WL_SHM_FORMAT_ABGR16161616F, "ABGR16161616F"}, 78 | {WL_SHM_FORMAT_XYUV8888, "XYUV8888"}, 79 | {WL_SHM_FORMAT_VUY888, "VUY888"}, 80 | {WL_SHM_FORMAT_VUY101010, "VUY101010"}, 81 | {WL_SHM_FORMAT_Y210, "Y210"}, 82 | {WL_SHM_FORMAT_Y212, "Y212"}, 83 | {WL_SHM_FORMAT_Y216, "Y216"}, 84 | {WL_SHM_FORMAT_Y410, "Y410"}, 85 | {WL_SHM_FORMAT_Y412, "Y412"}, 86 | {WL_SHM_FORMAT_Y416, "Y416"}, 87 | {WL_SHM_FORMAT_XVYU2101010, "XVYU2101010"}, 88 | {WL_SHM_FORMAT_XVYU12_16161616, "XVYU12_16161616"}, 89 | {WL_SHM_FORMAT_XVYU16161616, "XVYU16161616"}, 90 | {WL_SHM_FORMAT_Y0L0, "Y0L0"}, 91 | {WL_SHM_FORMAT_X0L0, "X0L0"}, 92 | {WL_SHM_FORMAT_Y0L2, "Y0L2"}, 93 | {WL_SHM_FORMAT_X0L2, "X0L2"}, 94 | {WL_SHM_FORMAT_YUV420_8BIT, "YUV420_8BIT"}, 95 | {WL_SHM_FORMAT_YUV420_10BIT, "YUV420_10BIT"}, 96 | {WL_SHM_FORMAT_XRGB8888_A8, "XRGB8888_A8"}, 97 | {WL_SHM_FORMAT_XBGR8888_A8, "XBGR8888_A8"}, 98 | {WL_SHM_FORMAT_RGBX8888_A8, "RGBX8888_A8"}, 99 | {WL_SHM_FORMAT_BGRX8888_A8, "BGRX8888_A8"}, 100 | {WL_SHM_FORMAT_RGB888_A8, "RGB888_A8"}, 101 | {WL_SHM_FORMAT_BGR888_A8, "BGR888_A8"}, 102 | {WL_SHM_FORMAT_RGB565_A8, "RGB565_A8"}, 103 | {WL_SHM_FORMAT_BGR565_A8, "BGR565_A8"}, 104 | {WL_SHM_FORMAT_NV24, "NV24"}, 105 | {WL_SHM_FORMAT_NV42, "NV42"}, 106 | {WL_SHM_FORMAT_P210, "P210"}, 107 | {WL_SHM_FORMAT_P010, "P010"}, 108 | {WL_SHM_FORMAT_P012, "P012"}, 109 | {WL_SHM_FORMAT_P016, "P016"}, 110 | {WL_SHM_FORMAT_AXBXGXRX106106106106, "AXBXGXRX106106106106"}, 111 | {WL_SHM_FORMAT_NV15, "NV15"}, 112 | {WL_SHM_FORMAT_Q410, "Q410"}, 113 | {WL_SHM_FORMAT_Q401, "Q401"}, 114 | #if WAYLAND_VERSION_MAJOR > 1 || WAYLAND_VERSION_MINOR >= 20 115 | {WL_SHM_FORMAT_XRGB16161616, "XRGB16161616"}, 116 | {WL_SHM_FORMAT_XBGR16161616, "XBGR16161616"}, 117 | {WL_SHM_FORMAT_ARGB16161616, "ARGB16161616"}, 118 | {WL_SHM_FORMAT_ABGR16161616, "ABGR16161616"}, 119 | #endif 120 | }; 121 | #endif 122 | -------------------------------------------------------------------------------- /shm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | struct damage; 13 | 14 | struct buffer { 15 | int width; 16 | int height; 17 | int stride; 18 | 19 | void *data; 20 | 21 | struct wl_buffer *wl_buf; 22 | pixman_image_t **pix; 23 | size_t pix_instances; 24 | 25 | unsigned age; 26 | 27 | /* 28 | * First item in the array is used to track frame-to-frame 29 | * damage. This is used when re-applying damage from the last 30 | * frame, when the compositor doesn't release buffers immediately 31 | * (forcing us to double buffer) 32 | * 33 | * The remaining items are used to track surface damage. Each 34 | * worker thread adds its own cell damage to "its" region. When 35 | * the frame is done, all damage is converted to a single region, 36 | * which is then used in calls to wl_surface_damage_buffer(). 37 | */ 38 | pixman_region32_t *dirty; 39 | }; 40 | 41 | void shm_fini(void); 42 | void shm_set_max_pool_size(off_t max_pool_size); 43 | 44 | struct buffer_chain; 45 | struct buffer_chain *shm_chain_new( 46 | struct wl_shm *shm, bool scrollable, size_t pix_instances); 47 | void shm_chain_free(struct buffer_chain *chain); 48 | 49 | /* 50 | * Returns a single buffer. 51 | * 52 | * May returned a cached buffer. If so, the buffer's age indicates how 53 | * many shm_get_buffer() calls have been made for the same 54 | * width/height while the buffer was still busy. 55 | * 56 | * A newly allocated buffer has an age of 1234. 57 | */ 58 | struct buffer *shm_get_buffer( 59 | struct buffer_chain *chain, int width, int height, bool with_alpha); 60 | /* 61 | * Returns many buffers, described by 'info', all sharing the same SHM 62 | * buffer pool. 63 | * 64 | * Never returns cached buffers. However, the newly created buffers 65 | * are all inserted into the regular buffer cache, and are treated 66 | * just like buffers created by shm_get_buffer(). 67 | * 68 | * This function is useful when allocating many small buffers, with 69 | * (roughly) the same life time. 70 | * 71 | * Buffers are tagged for immediate purging, and will be destroyed as 72 | * soon as the compositor releases them. 73 | */ 74 | void shm_get_many( 75 | struct buffer_chain *chain, size_t count, 76 | int widths[static count], int heights[static count], 77 | struct buffer *bufs[static count], bool with_alpha); 78 | 79 | void shm_did_not_use_buf(struct buffer *buf); 80 | 81 | bool shm_can_scroll(const struct buffer *buf); 82 | bool shm_scroll(struct buffer *buf, int rows, 83 | int top_margin, int top_keep_rows, 84 | int bottom_margin, int bottom_keep_rows); 85 | 86 | void shm_addref(struct buffer *buf); 87 | void shm_unref(struct buffer *buf); 88 | 89 | void shm_purge(struct buffer_chain *chain); 90 | -------------------------------------------------------------------------------- /sixel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "terminal.h" 4 | 5 | #define SIXEL_MAX_COLORS 1024u 6 | #define SIXEL_MAX_WIDTH 10000u 7 | #define SIXEL_MAX_HEIGHT 10000u 8 | 9 | typedef void (*sixel_put)(struct terminal *term, uint8_t c); 10 | 11 | void sixel_fini(struct terminal *term); 12 | 13 | sixel_put sixel_init(struct terminal *term, int p1, int p2, int p3); 14 | void sixel_unhook(struct terminal *term); 15 | 16 | void sixel_destroy(struct sixel *sixel); 17 | void sixel_destroy_all(struct terminal *term); 18 | 19 | void sixel_scroll_up(struct terminal *term, int rows); 20 | void sixel_scroll_down(struct terminal *term, int rows); 21 | 22 | void sixel_cell_size_changed(struct terminal *term); 23 | void sixel_sync_cache(const struct terminal *term, struct sixel *sixel); 24 | 25 | void sixel_reflow_grid(struct terminal *term, struct grid *grid); 26 | 27 | /* Shortcut for sixel_reflow_grid(normal) + sixel_reflow_grid(alt) */ 28 | void sixel_reflow(struct terminal *term); 29 | 30 | /* 31 | * Remove sixel data from the specified location. Used when printing 32 | * or erasing characters, and when emitting new sixel images, to 33 | * remove sixel data that would otherwise be rendered on-top. 34 | * 35 | * Row numbers are relative to the current grid offset 36 | */ 37 | void sixel_overwrite_by_rectangle( 38 | struct terminal *term, int row, int col, int height, int width); 39 | void sixel_overwrite_by_row(struct terminal *term, int row, int col, int width); 40 | void sixel_overwrite_at_cursor(struct terminal *term, int width); 41 | 42 | void sixel_colors_report_current(struct terminal *term); 43 | void sixel_colors_reset(struct terminal *term); 44 | void sixel_colors_set(struct terminal *term, unsigned count); 45 | void sixel_colors_report_max(struct terminal *term); 46 | 47 | void sixel_geometry_report_current(struct terminal *term); 48 | void sixel_geometry_reset(struct terminal *term); 49 | void sixel_geometry_set(struct terminal *term, unsigned width, unsigned height); 50 | void sixel_geometry_report_max(struct terminal *term); 51 | -------------------------------------------------------------------------------- /slave.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | 6 | #include "config.h" 7 | #include "user-notification.h" 8 | 9 | pid_t slave_spawn( 10 | int ptmx, int argc, const char *cwd, char *const *argv, const char *const *envp, 11 | const env_var_list_t *extra_env_vars, const char *term_env, 12 | const char *conf_shell, bool login_shell, 13 | const user_notifications_t *notifications); 14 | -------------------------------------------------------------------------------- /spawn.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "config.h" 7 | #include "reaper.h" 8 | 9 | pid_t spawn(struct reaper *reaper, const char *cwd, char *const argv[], 10 | int stdin_fd, int stdout_fd, int stderr_fd, 11 | reaper_cb cb, void *cb_data, const char *xdg_activation_token); 12 | 13 | bool spawn_expand_template( 14 | const struct config_spawn_template *template, 15 | size_t key_count, const char *key_names[static key_count], 16 | const char *key_values[static key_count], size_t *argc, char ***argv); 17 | -------------------------------------------------------------------------------- /stride.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | static inline int 6 | stride_for_format_and_width(pixman_format_code_t format, int width) 7 | { 8 | return (((PIXMAN_FORMAT_BPP(format) * width + 7) / 8 + 4 - 1) & -4); 9 | } 10 | -------------------------------------------------------------------------------- /subprojects/fcft.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://codeberg.org/dnkl/fcft.git 3 | revision = master 4 | -------------------------------------------------------------------------------- /subprojects/tllist.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://codeberg.org/dnkl/tllist.git 3 | revision = master 4 | -------------------------------------------------------------------------------- /subprojects/wayland-protocols.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://gitlab.freedesktop.org/wayland/wayland-protocols.git 3 | revision = main 4 | -------------------------------------------------------------------------------- /tests/meson.build: -------------------------------------------------------------------------------- 1 | config_test = executable( 2 | 'test-config', 3 | 'test-config.c', 4 | wl_proto_headers, 5 | link_with: [common, tokenize], 6 | dependencies: [pixman, xkb, fontconfig, wayland_client, fcft, tllist]) 7 | 8 | test('config', config_test) 9 | -------------------------------------------------------------------------------- /themes/aeroroot: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Aero root theme 3 | 4 | [cursor] 5 | color=1a1a1a 9fd5f5 6 | 7 | [colors] 8 | foreground=dedeef 9 | background=1a1a1a 10 | 11 | regular0=1a1a1a 12 | regular1=ff3a3a 13 | regular2=3aef3a 14 | regular3=e6e61a 15 | regular4=1a7eff 16 | regular5=df3adf 17 | regular6=3ff0e0 18 | regular7=dadada 19 | 20 | bright0=5a5a5a 21 | bright1=ffaaaa 22 | bright2=aaf3aa 23 | bright3=f3f35a 24 | bright4=6abaff 25 | bright5=e5aae5 26 | bright6=aafff0 27 | bright7=f3f3f3 28 | 29 | dim0=000000 30 | dim1=b71a1a 31 | dim2=1ab71a 32 | dim3=b5b50a 33 | dim4=0A4FAA 34 | dim5=a71aa7 35 | dim6=1AA59F 36 | dim7=a5a5a5 37 | -------------------------------------------------------------------------------- /themes/apprentice: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # https://github.com/romainl/Apprentice 3 | 4 | [cursor] 5 | color=262626 6c6c6c 6 | 7 | [colors] 8 | foreground=bcbcbc 9 | background=262626 10 | regular0=1c1c1c 11 | regular1=af5f5f 12 | regular2=5f875f 13 | regular3=87875f 14 | regular4=5f87af 15 | regular5=5f5f87 16 | regular6=5f8787 17 | regular7=6c6c6c 18 | bright0=444444 19 | bright1=ff8700 20 | bright2=87af87 21 | bright3=ffffaf 22 | bright4=87afd7 23 | bright5=8787af 24 | bright6=5fafaf 25 | bright7=ffffff 26 | # selection-foreground=bcbcbc 27 | # selection-background=3a3e4e -------------------------------------------------------------------------------- /themes/ayu-mirage: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Ayu Mirage 3 | # description: a theme based on Ayu Mirage for Sublime Text (original: https://github.com/dempfi/ayu) 4 | 5 | [cursor] 6 | color = ffcc66 665a44 7 | 8 | [colors] 9 | foreground = cccac2 10 | background = 242936 11 | 12 | regular0 = 242936 # black 13 | regular1 = f28779 # red 14 | regular2 = d5ff80 # green 15 | regular3 = ffd173 # yellow 16 | regular4 = 73d0ff # blue 17 | regular5 = dfbfff # magenta 18 | regular6 = 5ccfe6 # cyan 19 | regular7 = cccac2 # white 20 | 21 | bright0 = fcfcfc # bright black 22 | bright1 = f07171 # bright red 23 | bright2 = 86b300 # bright gree 24 | bright3 = f2ae49 # bright yellow 25 | bright4 = 399ee6 # bright blue 26 | bright5 = a37acc # bright magenta 27 | bright6 = 55b4d4 # bright cyan 28 | bright7 = 5c6166 # bright white 29 | -------------------------------------------------------------------------------- /themes/catppuccin-frappe: -------------------------------------------------------------------------------- 1 | # _*_ conf _*_ 2 | # Catppuccin Frappe 3 | 4 | [colors] 5 | foreground=c6d0f5 6 | background=303446 7 | 8 | regular0=51576d 9 | regular1=e78284 10 | regular2=a6d189 11 | regular3=e5c890 12 | regular4=8caaee 13 | regular5=f4b8e4 14 | regular6=81c8be 15 | regular7=b5bfe2 16 | 17 | bright0=626880 18 | bright1=e78284 19 | bright2=a6d189 20 | bright3=e5c890 21 | bright4=8caaee 22 | bright5=f4b8e4 23 | bright6=81c8be 24 | bright7=a5adce 25 | 26 | selection-foreground=c6d0f5 27 | selection-background=4f5369 28 | 29 | search-box-no-match=232634 e78284 30 | search-box-match=c6d0f5 414559 31 | 32 | jump-labels=232634 ef9f76 33 | urls=8caaee 34 | -------------------------------------------------------------------------------- /themes/catppuccin-latte: -------------------------------------------------------------------------------- 1 | # _*_ conf _*_ 2 | # Catppuccin Latte 3 | 4 | [colors] 5 | foreground=4c4f69 6 | background=eff1f5 7 | 8 | regular0=5c5f77 9 | regular1=d20f39 10 | regular2=40a02b 11 | regular3=df8e1d 12 | regular4=1e66f5 13 | regular5=ea76cb 14 | regular6=179299 15 | regular7=acb0be 16 | 17 | bright0=6c6f85 18 | bright1=d20f39 19 | bright2=40a02b 20 | bright3=df8e1d 21 | bright4=1e66f5 22 | bright5=ea76cb 23 | bright6=179299 24 | bright7=bcc0cc 25 | 26 | selection-foreground=4c4f69 27 | selection-background=ccced7 28 | 29 | search-box-no-match=dce0e8 d20f39 30 | search-box-match=4c4f69 ccd0da 31 | 32 | jump-labels=dce0e8 fe640b 33 | urls=1e66f5 34 | -------------------------------------------------------------------------------- /themes/catppuccin-macchiato: -------------------------------------------------------------------------------- 1 | # _*_ conf _*_ 2 | # Catppuccin Macchiato 3 | 4 | [colors] 5 | foreground=cad3f5 6 | background=24273a 7 | 8 | regular0=494d64 9 | regular1=ed8796 10 | regular2=a6da95 11 | regular3=eed49f 12 | regular4=8aadf4 13 | regular5=f5bde6 14 | regular6=8bd5ca 15 | regular7=b8c0e0 16 | 17 | bright0=5b6078 18 | bright1=ed8796 19 | bright2=a6da95 20 | bright3=eed49f 21 | bright4=8aadf4 22 | bright5=f5bde6 23 | bright6=8bd5ca 24 | bright7=a5adcb 25 | 26 | selection-foreground=cad3f5 27 | selection-background=454a5f 28 | 29 | search-box-no-match=181926 ed8796 30 | search-box-match=cad3f5 363a4f 31 | 32 | jump-labels=181926 f5a97f 33 | urls=8aadf4 34 | -------------------------------------------------------------------------------- /themes/catppuccin-mocha: -------------------------------------------------------------------------------- 1 | # _*_ conf _*_ 2 | # Catppuccin Mocha 3 | 4 | [colors] 5 | foreground=cdd6f4 6 | background=1e1e2e 7 | 8 | regular0=45475a 9 | regular1=f38ba8 10 | regular2=a6e3a1 11 | regular3=f9e2af 12 | regular4=89b4fa 13 | regular5=f5c2e7 14 | regular6=94e2d5 15 | regular7=bac2de 16 | 17 | bright0=585b70 18 | bright1=f38ba8 19 | bright2=a6e3a1 20 | bright3=f9e2af 21 | bright4=89b4fa 22 | bright5=f5c2e7 23 | bright6=94e2d5 24 | bright7=a6adc8 25 | 26 | selection-foreground=cdd6f4 27 | selection-background=414356 28 | 29 | search-box-no-match=11111b f38ba8 30 | search-box-match=cdd6f4 313244 31 | 32 | jump-labels=11111b fab387 33 | urls=89b4fa 34 | -------------------------------------------------------------------------------- /themes/chiba-dark: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Chiba Dark 3 | # author: ayushnix (https://sr.ht/~ayushnix) 4 | # description: A dark theme with bright cyberpunk colors (WCAG AAA compliant) 5 | 6 | [cursor] 7 | color = 181818 cdcdcd 8 | 9 | [colors] 10 | foreground = cdcdcd 11 | background = 181818 12 | regular0 = 181818 13 | regular1 = ff8599 14 | regular2 = 00c545 15 | regular3 = de9d00 16 | regular4 = 00b4ff 17 | regular5 = fd71f8 18 | regular6 = 00bfae 19 | regular7 = cdcdcd 20 | bright0 = 262626 21 | bright1 = ff9eb2 22 | bright2 = 19de5e 23 | bright3 = f7b619 24 | bright4 = 19cdff 25 | bright5 = ff8aff 26 | bright6 = 19d8c7 27 | bright7 = dadada 28 | -------------------------------------------------------------------------------- /themes/derp: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Derp 3 | 4 | [cursor] 5 | color=000000 ffffff 6 | 7 | [colors] 8 | foreground=ffffff 9 | background=000000 10 | regular0=111111 11 | regular1=d36265 12 | regular2=aece91 13 | regular3=e7e18c 14 | regular4=5297cf 15 | regular5=963c59 16 | regular6=5e7175 17 | regular7=bebebe 18 | bright0=666666 19 | bright1=ef8171 20 | bright2=cfefb3 21 | bright3=fff796 22 | bright4=74b8ef 23 | bright5=b85e7b 24 | bright6=a3babf 25 | bright7=ffffff 26 | -------------------------------------------------------------------------------- /themes/deus: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Deus 3 | # Color palette based on: https://github.com/ajmwagar/vim-deus 4 | 5 | [cursor] 6 | color=2c323b eaeaea 7 | 8 | [colors] 9 | background=2c323b 10 | foreground=eaeaea 11 | regular0=242a32 12 | regular1=d54e53 13 | regular2=98c379 14 | regular3=e5c07b 15 | regular4=83a598 16 | regular5=c678dd 17 | regular6=70c0ba 18 | regular7=eaeaea 19 | bright0=666666 20 | bright1=ec3e45 21 | bright2=90c966 22 | bright3=edbf69 23 | bright4=73ba9f 24 | bright5=c858e9 25 | bright6=2bcec2 26 | bright7=ffffff 27 | 28 | # Enable if prefer Deus colors instead of inverterd fg/bg for 29 | # highlighting (mouse selection) 30 | # selection-foreground=2c323b 31 | # selection-background=eaeaea 32 | -------------------------------------------------------------------------------- /themes/dracula: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Dracula 3 | 4 | [cursor] 5 | color=282a36 f8f8f2 6 | 7 | [colors] 8 | foreground=f8f8f2 9 | background=282a36 10 | regular0=000000 # black 11 | regular1=ff5555 # red 12 | regular2=50fa7b # green 13 | regular3=f1fa8c # yellow 14 | regular4=bd93f9 # blue 15 | regular5=ff79c6 # magenta 16 | regular6=8be9fd # cyan 17 | regular7=bfbfbf # white 18 | bright0=4d4d4d # bright black 19 | bright1=ff6e67 # bright red 20 | bright2=5af78e # bright green 21 | bright3=f4f99d # bright yellow 22 | bright4=caa9fa # bright blue 23 | bright5=ff92d0 # bright magenta 24 | bright6=9aedfe # bright cyan 25 | bright7=e6e6e6 # bright white -------------------------------------------------------------------------------- /themes/dracula-iterm: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Dracula iTerm2 variant 3 | 4 | [cursor] 5 | color=ffffff bbbbbb 6 | 7 | [colors] 8 | foreground=f8f8f2 9 | background=1e1f29 10 | regular0=000000 # black 11 | regular1=ff5555 # red 12 | regular2=50fa7b # green 13 | regular3=f1fa8c # yellow 14 | regular4=bd93f9 # blue 15 | regular5=ff79c6 # magenta 16 | regular6=8be9fd # cyan 17 | regular7=bbbbbb # white 18 | bright0=555555 # bright black 19 | bright1=ff5555 # bright red 20 | bright2=50fa7b # bright green 21 | bright3=f1fa8c # bright yellow 22 | bright4=bd93f9 # bright blue 23 | bright5=ff79c6 # bright magenta 24 | bright6=8be9fd # bright cyan 25 | bright7=ffffff # bright white 26 | -------------------------------------------------------------------------------- /themes/electrophoretic: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Electrophoretic 3 | # Theme for electrophoretic displays (like e-ink) which usually supports 4 | # 16 levels of grays. This theme aims to maximize the contrast between the 5 | # text and the white background. 6 | # author: Eugen Rahaian 7 | 8 | [cursor] 9 | color=ffffff 515151 10 | 11 | [colors] 12 | background= ffffff 13 | foreground= 000000 14 | 15 | # The colors are sorted based on their luminance, so we can more easily assign 16 | # them a gray level. 17 | # grayscale order: black_0 blue_4 red_1 magenta_5 green_2 cyan_6 yellow_3 white_7 18 | regular0= ffffff 19 | regular4= 616161 20 | regular1= 515151 21 | regular5= 414141 22 | regular2= 313131 23 | regular6= 212121 24 | regular3= 111111 25 | regular7= 000000 26 | # Here, we also stay away from the white background by reusing the dark gray levels 27 | # from above, with small variations 28 | bright0= 818181 29 | bright4= 717171 30 | bright1= 616161 31 | bright5= 515151 32 | bright2= 414141 33 | bright6= 313131 34 | bright3= 212121 35 | bright7= 111111 36 | -------------------------------------------------------------------------------- /themes/gruvbox-dark: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Gruvbox 3 | 4 | [colors] 5 | background=282828 6 | foreground=ebdbb2 7 | regular0=282828 8 | regular1=cc241d 9 | regular2=98971a 10 | regular3=d79921 11 | regular4=458588 12 | regular5=b16286 13 | regular6=689d6a 14 | regular7=a89984 15 | bright0=928374 16 | bright1=fb4934 17 | bright2=b8bb26 18 | bright3=fabd2f 19 | bright4=83a598 20 | bright5=d3869b 21 | bright6=8ec07c 22 | bright7=ebdbb2 23 | -------------------------------------------------------------------------------- /themes/gruvbox-light: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Gruvbox - Light 3 | 4 | [colors] 5 | background=fbf1c7 6 | foreground=3c3836 7 | regular0=fbf1c7 8 | regular1=cc241d 9 | regular2=98971a 10 | regular3=d79921 11 | regular4=458588 12 | regular5=b16286 13 | regular6=689d6a 14 | regular7=7c6f64 15 | bright0=928374 16 | bright1=9d0006 17 | bright2=79740e 18 | bright3=b57614 19 | bright4=076678 20 | bright5=8f3f71 21 | bright6=427b58 22 | bright7=3c3836 23 | -------------------------------------------------------------------------------- /themes/hacktober: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | [cursor] 3 | color=141414 c9c9c9 4 | 5 | [colors] 6 | foreground=c9c9c9 7 | background=141414 8 | regular0=191918 # black 9 | regular1=b34538 # red 10 | regular2=587744 # green 11 | regular3=d08949 # yellow 12 | regular4=206ec5 # blue 13 | regular5=864651 # magenta 14 | regular6=ac9166 # cyan 15 | regular7=f1eee7 # white 16 | bright0=2c2b2a # bright black 17 | bright1=b33323 # bright red 18 | bright2=42824a # bright green 19 | bright3=c75a22 # bright yellow 20 | bright4=5389c5 # bright blue 21 | bright5=e795a5 # bright magenta 22 | bright6=ebc587 # bright cyan 23 | bright7=ffffff # bright white 24 | -------------------------------------------------------------------------------- /themes/jetbrains-darcula: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # JetBrains Darcula 3 | # Palette based on the same theme from https://github.com/dexpota/kitty-themes 4 | 5 | [cursor] 6 | color=202020 ffffff 7 | 8 | [colors] 9 | background=202020 10 | foreground=adadad 11 | regular0=000000 # black 12 | regular1=fa5355 # red 13 | regular2=126e00 # green 14 | regular3=c2c300 # yellow 15 | regular4=4581eb # blue 16 | regular5=fa54ff # magenta 17 | regular6=33c2c1 # cyan 18 | regular7=adadad # white 19 | bright0=545454 # bright black 20 | bright1=fb7172 # bright red 21 | bright2=67ff4f # bright green 22 | bright3=ffff00 # bright yellow 23 | bright4=6d9df1 # bright blue 24 | bright5=fb82ff # bright magenta 25 | bright6=60d3d1 # bright cyan 26 | bright7=eeeeee # bright white 27 | # selection-foreground=202020 28 | # selection-background=1a3272 29 | -------------------------------------------------------------------------------- /themes/kitty: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | 3 | [cursor] 4 | color=111111 cccccc 5 | 6 | [colors] 7 | foreground=dddddd 8 | background=000000 9 | regular0=000000 # black 10 | regular1=cc0403 # red 11 | regular2=19cb00 # green 12 | regular3=cecb00 # yellow 13 | regular4=0d73cc # blue 14 | regular5=cb1ed1 # magenta 15 | regular6=0dcdcd # cyan 16 | regular7=dddddd # white 17 | bright0=767676 # bright black 18 | bright1=f2201f # bright red 19 | bright2=23fd00 # bright green 20 | bright3=fffd00 # bright yellow 21 | bright4=1a8fff # bright blue 22 | bright5=fd28ff # bright magenta 23 | bright6=14ffff # bright cyan 24 | bright7=ffffff # bright white 25 | -------------------------------------------------------------------------------- /themes/material-amber: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Material Amber 3 | # Based on material.io guidelines with Amber 50 background 4 | 5 | [cursor] 6 | color=fff8e1 21201d 7 | 8 | [colors] 9 | foreground = 21201d 10 | background = fff8e1 11 | 12 | regular0 = 21201d # black 13 | regular1 = cd4340 # red 14 | regular2 = 498d49 # green 15 | regular3 = fab32d # yellow 16 | regular4 = 3378c4 # blue 17 | regular5 = b83269 # magenta 18 | regular6 = 21929a # cyan 19 | regular7 = ffd7d7 # white 20 | 21 | bright0 = 66635a # bright black 22 | bright1 = dd7b72 # bright red 23 | bright2 = 82ae78 # bright green 24 | bright3 = fbc870 # bright yellow 25 | bright4 = 73a0cd # bright blue 26 | bright5 = ce6f8e # bright magenta 27 | bright6 = 548c94 # bright cyan 28 | bright7 = ffe1da # bright white 29 | 30 | dim0 = 9e9a8c # dim black 31 | dim1 = e9a99b # dim red 32 | dim2 = b0c99f # dim green 33 | dim3 = fdda9a # dim yellow 34 | dim4 = a6c0d4 # dim blue 35 | dim5 = e0a1ad # dim magenta 36 | dim6 = 3c6064 # dim cyan 37 | dim7 = ffe9dd # dim white 38 | 39 | # selection-foreground=fff8e1 40 | # selection-background=21201d 41 | -------------------------------------------------------------------------------- /themes/material-design: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Material 3 | # From https://github.com/MartinSeeler/iterm2-material-design 4 | 5 | [colors] 6 | foreground=ECEFF1 7 | background=263238 8 | regular0=546E7A # black 9 | regular1=FF5252 # red 10 | regular2=5CF19E # green 11 | regular3=FFD740 # yellow 12 | regular4=40C4FF # blue 13 | regular5=FF4081 # magenta 14 | regular6=64FCDA # cyan 15 | regular7=FFFFFF # white 16 | bright0=B0BEC5 # bright black 17 | bright1=FF8A80 # bright red 18 | bright2=B9F6CA # bright green 19 | bright3=FFE57F # bright yellow 20 | bright4=80D8FF # bright blue 21 | bright5=FF80AB # bright magenta 22 | bright6=A7FDEB # bright cyan 23 | bright7=FFFFFF # bright white 24 | # selection-foreground=ECEFF1 25 | # selection-background=607D8B 26 | -------------------------------------------------------------------------------- /themes/modus-operandi: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # 3 | # modus-operandi 4 | # See: https://protesilaos.com/emacs/modus-themes 5 | # 6 | [colors] 7 | background=ffffff 8 | foreground=000000 9 | regular0=000000 10 | regular1=a60000 11 | regular2=005e00 12 | regular3=813e00 13 | regular4=0031a9 14 | regular5=721045 15 | regular6=00538b 16 | regular7=bfbfbf 17 | bright0=595959 18 | bright1=972500 19 | bright2=315b00 20 | bright3=70480f 21 | bright4=2544bb 22 | bright5=5317ac 23 | bright6=005a5f 24 | bright7=ffffff 25 | -------------------------------------------------------------------------------- /themes/modus-vivendi: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # 3 | # modus-vivendi 4 | # See: https://protesilaos.com/emacs/modus-themes 5 | # 6 | 7 | [colors] 8 | background=000000 9 | foreground=ffffff 10 | regular0=000000 11 | regular1=ff8059 12 | regular2=44bc44 13 | regular3=d0bc00 14 | regular4=2fafff 15 | regular5=feacd0 16 | regular6=00d3d0 17 | regular7=bfbfbf 18 | bright0=595959 19 | bright1=ef8b50 20 | bright2=70b900 21 | bright3=c0c530 22 | bright4=79a8ff 23 | bright5=b6a0ff 24 | bright6=6ae4b9 25 | bright7=ffffff 26 | -------------------------------------------------------------------------------- /themes/monokai-pro: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Monokai Pro 3 | 4 | [colors] 5 | background=2D2A2E 6 | foreground=FCFCFA 7 | regular0=403E41 8 | regular1=FF6188 9 | regular2=A9DC76 10 | regular3=FFD866 11 | regular4=FC9867 12 | regular5=AB9DF2 13 | regular6=78DCE8 14 | regular7=FCFCFA 15 | bright0=727072 16 | bright1=FF6188 17 | bright2=A9DC76 18 | bright3=FFD866 19 | bright4=FC9867 20 | bright5=AB9DF2 21 | bright6=78DCE8 22 | bright7=FCFCFA 23 | -------------------------------------------------------------------------------- /themes/moonfly: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # moonfly 3 | # Based on https://github.com/bluz71/vim-moonfly-colors 4 | 5 | [cursor] 6 | color = 080808 9e9e9e 7 | 8 | [colors] 9 | foreground = b2b2b2 10 | background = 080808 11 | 12 | # selection-foreground = 080808 13 | # selection-background = b2ceee 14 | 15 | regular0 = 323437 16 | regular1 = ff5454 17 | regular2 = 8cc85f 18 | regular3 = e3c78a 19 | regular4 = 80a0ff 20 | regular5 = d183e8 21 | regular6 = 79dac8 22 | regular7 = c6c6c6 23 | 24 | bright0 = 949494 25 | bright1 = ff5189 26 | bright2 = 36c692 27 | bright3 = c2c292 28 | bright4 = 74b2ff 29 | bright5 = ae81ff 30 | bright6 = 85dc85 31 | bright7 = e4e4e4 32 | -------------------------------------------------------------------------------- /themes/neon: -------------------------------------------------------------------------------- 1 | # 2 | # vim: ft=dosini 3 | # 4 | # Neon 5 | # 6 | # https://xcolors.net/neon 7 | # 8 | 9 | [colors] 10 | foreground=f8f8f8 11 | background=171717 12 | regular0=171717 13 | regular1=d81765 14 | regular2=97d01a 15 | regular3=ffa800 16 | regular4=16b1fb 17 | regular5=ff2491 18 | regular6=0fdcb6 19 | regular7=ebebeb 20 | bright0=38252c 21 | bright1=ff0000 22 | bright2=76b639 23 | bright3=e1a126 24 | bright4=289cd5 25 | bright5=ff2491 26 | bright6=0a9b81 27 | bright7=f8f8f8 28 | -------------------------------------------------------------------------------- /themes/nightfly: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # nightfly 3 | # Based on https://github.com/bluz71/vim-nightfly-guicolors 4 | 5 | [cursor] 6 | color = 080808 9ca1aa 7 | 8 | [colors] 9 | foreground = acb4c2 10 | background = 011627 11 | 12 | # selection-foreground = 080808 13 | # selection-background = b2ceee 14 | 15 | regular0 = 1d3b53 16 | regular1 = fc514e 17 | regular2 = a1cd5e 18 | regular3 = e3d18a 19 | regular4 = 82aaff 20 | regular5 = c792ea 21 | regular6 = 7fdbca 22 | regular7 = a1aab8 23 | 24 | bright0 = 7c8f8f 25 | bright1 = ff5874 26 | bright2 = 21c7a8 27 | bright3 = ecc48d 28 | bright4 = 82aaff 29 | bright5 = ae81ff 30 | bright6 = ae81ff 31 | bright7 = d6deeb 32 | -------------------------------------------------------------------------------- /themes/noirblaze: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # noirblaze-kitty 3 | # https://github.com/n1ghtmare/noirblaze-kitty 4 | 5 | 6 | [cursor] 7 | color=121212 ff0088 8 | 9 | [colors] 10 | foreground=d5d5d5 11 | background=121212 12 | 13 | # selection-foreground=121212 14 | # selection-background=b0b0b0 15 | 16 | regular0=121212 # black 17 | regular1=ff0088 # red 18 | regular2=00ff77 # green 19 | regular3=ffffff # yellow 20 | regular4=b0b0b0 # blue 21 | regular5=7a7a7a # magenta 22 | regular6=787878 # cyan 23 | regular7=d5d5d5 # white 24 | bright0=737373 # bright black 25 | bright1=FD319E # bright red 26 | bright2=FD319E # bright green 27 | bright3=FDFDFD # bright yellow 28 | bright4=BEBEBE # bright blue 29 | bright5=939393 # bright magenta 30 | bright6=919191 # bright cyan 31 | bright7=f5f5f5 # bright white 32 | -------------------------------------------------------------------------------- /themes/nord: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Nord 3 | # author: Arctic Ice Studio , Sven Greb 4 | # description: „Nord“ — An arctic, north-bluish color palette 5 | # 6 | # this specific foot theme is based on nord-alacritty: 7 | # https://github.com/arcticicestudio/nord-alacritty/blob/develop/src/nord.yml 8 | 9 | [cursor] 10 | color = 2e3440 d8dee9 11 | 12 | [colors] 13 | foreground = d8dee9 14 | background = 2e3440 15 | 16 | # selection-foreground = d8dee9 17 | # selection-background = 4c566a 18 | 19 | regular0 = 3b4252 20 | regular1 = bf616a 21 | regular2 = a3be8c 22 | regular3 = ebcb8b 23 | regular4 = 81a1c1 24 | regular5 = b48ead 25 | regular6 = 88c0d0 26 | regular7 = e5e9f0 27 | 28 | bright0 = 4c566a 29 | bright1 = bf616a 30 | bright2 = a3be8c 31 | bright3 = ebcb8b 32 | bright4 = 81a1c1 33 | bright5 = b48ead 34 | bright6 = 8fbcbb 35 | bright7 = eceff4 36 | 37 | dim0 = 373e4d 38 | dim1 = 94545d 39 | dim2 = 809575 40 | dim3 = b29e75 41 | dim4 = 68809a 42 | dim5 = 8c738c 43 | dim6 = 6d96a5 44 | dim7 = aeb3bb 45 | -------------------------------------------------------------------------------- /themes/nordiq: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Nordiq 3 | 4 | [cursor] 5 | color=eeeeee 9f515a 6 | 7 | [colors] 8 | foreground=dbdee9 9 | background=0e1420 10 | regular0=5b6272 11 | regular1=bf616a 12 | regular2=a3be8c 13 | regular3=ebcb8b 14 | regular4=81a1c1 15 | regular5=b48ead 16 | regular6=88c0d0 17 | regular7=e5e9f0 18 | bright0=4c566a 19 | bright1=bf616a 20 | bright2=a3be8c 21 | bright3=ebcb8b 22 | bright4=81a1c1 23 | bright5=b48ead 24 | bright6=8fbcbb 25 | bright7=eceff4 26 | 27 | -------------------------------------------------------------------------------- /themes/nvim-dark: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Neovim Dark theme 3 | # Uses the dark color palette from the default Neovim color scheme 4 | # See: https://github.com/neovim/neovim/blob/fb6c059dc55c8d594102937be4dd70f5ff51614a/src/nvim/highlight_group.c#L419 5 | 6 | [cursor] 7 | color=14161b e0e2ea # NvimDarkGrey2 NvimLightGrey2 8 | 9 | [colors] 10 | foreground=e0e2ea # NvimLightGrey2 11 | background=14161b # NvimDarkGrey2 12 | 13 | selection-foreground=e0e2ea # NvimLightGrey2 14 | selection-background=4f5258 # NvimDarkGrey4 15 | 16 | regular0=07080d # NvimDarkGrey1 17 | regular1=ffc0b9 # NvimLightRed 18 | regular2=b3f6c0 # NvimLightGreen 19 | regular3=fce094 # NvimLightYellow 20 | regular4=a6dbff # NvimLightBlue 21 | regular5=ffcaff # NvimLightMagenta 22 | regular6=8cf8f7 # NvimLightCyan 23 | regular7=c4c6cd # NvimLightGrey3 24 | 25 | bright0=2c2e33 # NvimDarkGrey3 26 | bright1=ffc0b9 # NvimLightRed 27 | bright2=b3f6c0 # NvimLightGreen 28 | bright3=fce094 # NvimLightYellow 29 | bright4=a6dbff # NvimLightBlue 30 | bright5=ffcaff # NvimLightMagenta 31 | bright6=8cf8f7 # NvimLightCyan 32 | bright7=eef1f8 # NvimLightGrey1 33 | -------------------------------------------------------------------------------- /themes/nvim-light: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Neovim Light theme 3 | # Uses the light color palette from the default Neovim color scheme 4 | # See: https://github.com/neovim/neovim/blob/fb6c059dc55c8d594102937be4dd70f5ff51614a/src/nvim/highlight_group.c#L334 5 | 6 | [cursor] 7 | color=e0e2ea 14161b # NvimLightGrey2 NvimDarkGrey2 8 | 9 | [colors] 10 | foreground=14161b # NvimDarkGrey2 11 | background=e0e2ea # NvimLightGrey2 12 | 13 | selection-foreground=14161b # NvimDarkGrey2 14 | selection-background=9b9ea4 # NvimLightGrey4 15 | 16 | regular0=eef1f8 # NvimLightGrey1 17 | regular1=590008 # NvimDarkRed 18 | regular2=005523 # NvimDarkGreen 19 | regular3=6b5300 # NvimDarkYellow 20 | regular4=004c73 # NvimDarkBlue 21 | regular5=470045 # NvimDarkMagenta 22 | regular6=007373 # NvimDarkCyan 23 | regular7=2c2e33 # NvimDarkGrey3 24 | 25 | bright0=c4c6cd # NvimLightGrey3 26 | bright1=590008 # NvimDarkRed 27 | bright2=005523 # NvimDarkGreen 28 | bright3=6b5300 # NvimDarkYellow 29 | bright4=004c73 # NvimDarkBlue 30 | bright5=470045 # NvimDarkMagenta 31 | bright6=007373 # NvimDarkCyan 32 | bright7=07080d # NvimDarkGrey1 33 | -------------------------------------------------------------------------------- /themes/onedark: -------------------------------------------------------------------------------- 1 | # OneDark 2 | # Palette based on the same theme from https://github.com/dexpota/kitty-themes 3 | 4 | [cursor] 5 | color=111111 cccccc 6 | 7 | [colors] 8 | foreground=979eab 9 | background=282c34 10 | regular0=282c34 # black 11 | regular1=e06c75 # red 12 | regular2=98c379 # green 13 | regular3=e5c07b # yellow 14 | regular4=61afef # blue 15 | regular5=be5046 # magenta 16 | regular6=56b6c2 # cyan 17 | regular7=979eab # white 18 | bright0=393e48 # bright black 19 | bright1=d19a66 # bright red 20 | bright2=56b6c2 # bright green 21 | bright3=e5c07b # bright yellow 22 | bright4=61afef # bright blue 23 | bright5=be5046 # bright magenta 24 | bright6=56b6c2 # bright cyan 25 | bright7=abb2bf # bright white 26 | # selection-foreground=282c34 27 | # selection-background=979eab 28 | -------------------------------------------------------------------------------- /themes/onehalf-dark: -------------------------------------------------------------------------------- 1 | # theme: One Half - dark version 2 | # author: Son A. Pham 3 | # repo: https://github.com/sonph/onehalf 4 | # 5 | # foot theme is based mainly on values from this specific file: 6 | # https://github.com/sonph/onehalf/blob/master/kitty/onehalf-dark.conf 7 | # + cursor colors from: 8 | # https://github.com/sonph/onehalf/blob/master/iterm/OneHalfDark.itermcolors 9 | 10 | [cursor] 11 | color=dcdfe4 a3b3cc 12 | 13 | [colors] 14 | foreground=dcdfe4 15 | background=282c34 16 | regular0=282c34 # black 17 | regular1=e06c75 # red 18 | regular2=98c379 # green 19 | regular3=e5c07b # yellow 20 | regular4=61afef # blue 21 | regular5=c678dd # magenta 22 | regular6=56b6c2 # cyan 23 | regular7=dcdfe4 # white 24 | bright0=5d677a # bright black 25 | bright1=e06c75 # bright red 26 | bright2=98c379 # bright green 27 | bright3=e5c07b # bright yellow 28 | bright4=61afef # bright blue 29 | bright5=c678dd # bright magenta 30 | bright6=56b6c2 # bright cyan 31 | bright7=dcdfe4 # bright white 32 | 33 | # Enable if prefer theme color for URL underline 34 | # urls=0087bd 35 | 36 | # Enable if prefer theme colors instead of inverterd fg/bg for 37 | # highlighting (mouse selection) 38 | # selection-foreground=000000 39 | # selection-background=fffacd 40 | -------------------------------------------------------------------------------- /themes/panda: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # http://panda.siamak.me/ 3 | 4 | [colors] 5 | # alpha=1.0 6 | background=1D1E20 7 | foreground=F0F0F0 8 | 9 | ## Normal/regular colors (color palette 0-7) 10 | regular0=1F1F20 # black 11 | regular1=FB055A # red 12 | regular2=26FFD4 # green 13 | regular3=26FFD4 # yellow 14 | regular4=5C9FFF # blue 15 | regular5=FC59A6 # magenta 16 | regular6=26FFD4 # cyan 17 | regular7=F0F0F0 # white 18 | 19 | ## Bright colors (color palette 8-15) 20 | bright0=5C6370 # bright black 21 | bright1=FB055A # bright red 22 | bright2=26FFD4 # bright green 23 | bright3=FEBE7E # bright yellow 24 | bright4=55ADFF # bright blue 25 | bright5=FD95D0 # bright magenta 26 | bright6=26FFD4 # bright cyan 27 | bright7=F0F0F0 # bright white -------------------------------------------------------------------------------- /themes/paper-color-dark: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # PaperColorDark 3 | # Palette based on https://github.com/NLKNguyen/papercolor-theme 4 | 5 | [cursor] 6 | color=1c1c1c eeeeee 7 | 8 | [colors] 9 | background=1c1c1c 10 | foreground=eeeeee 11 | regular0=1c1c1c # black 12 | regular1=af005f # red 13 | regular2=5faf00 # green 14 | regular3=d7af5f # yellow 15 | regular4=5fafd7 # blue 16 | regular5=808080 # magenta 17 | regular6=d7875f # cyan 18 | regular7=d0d0d0 # white 19 | bright0=bcbcbc # bright black 20 | bright1=5faf5f # bright red 21 | bright2=afd700 # bright green 22 | bright3=af87d7 # bright yellow 23 | bright4=ffaf00 # bright blue 24 | bright5=ff5faf # bright magenta 25 | bright6=00afaf # bright cyan 26 | bright7=5f8787 # bright white 27 | # selection-foreground=1c1c1c 28 | # selection-background=af87d7 29 | -------------------------------------------------------------------------------- /themes/paper-color-light: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # PaperColor Light 3 | # Palette based on https://github.com/NLKNguyen/papercolor-theme 4 | 5 | [cursor] 6 | color=eeeeee 444444 7 | 8 | [colors] 9 | background=eeeeee 10 | foreground=444444 11 | regular0=eeeeee # black 12 | regular1=af0000 # red 13 | regular2=008700 # green 14 | regular3=5f8700 # yellow 15 | regular4=0087af # blue 16 | regular5=878787 # magenta 17 | regular6=005f87 # cyan 18 | regular7=764e37 # white 19 | bright0=bcbcbc # bright black 20 | bright1=d70000 # bright red 21 | bright2=d70087 # bright green 22 | bright3=8700af # bright yellow 23 | bright4=d75f00 # bright blue 24 | bright5=d75f00 # bright magenta 25 | bright6=4c7a5d # bright cyan 26 | bright7=005faf # bright white 27 | # selection-foreground=eeeeee 28 | # selection-background=0087af 29 | -------------------------------------------------------------------------------- /themes/poimandres: -------------------------------------------------------------------------------- 1 | # Based on Poimandres color theme for kitti terminal emulator 2 | # https://github.com/ubmit/poimandres-kitty 3 | 4 | [cursor] 5 | color=1b1e28 ffffff 6 | 7 | [colors] 8 | foreground=a6accd 9 | background=1b1e28 10 | 11 | regular0=1b1e28 12 | regular1=d0679d 13 | regular2=5de4c7 14 | regular3=fffac2 15 | regular4=89ddff 16 | regular5=fcc5e9 17 | regular6=add7ff 18 | regular7=ffffff 19 | 20 | bright0=a6accd 21 | bright1=d0679d 22 | bright2=5de4c7 23 | bright3=fffac2 24 | bright4=add7ff 25 | bright5=fae4fc 26 | bright6=89ddff 27 | bright7=ffffff 28 | 29 | selection-background=28344a 30 | selection-foreground=a6accd 31 | -------------------------------------------------------------------------------- /themes/rezza: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: rezza 3 | # author: Doug Whiteley (rezza) 4 | # original URL: http://metawire.org/~rezza/index.php 5 | # currently available via: https://web.archive.org/web/20060207133656/http://metawire.org/~rezza/index.php?page=Configs 6 | # this palette was also posted here: 7 | # https://bbs.archlinux.org/viewtopic.php?id=17322 8 | # 9 | # more description: 10 | # original colors are similar to `phrakture` (https://github.com/f4cket/everycolorschemeivefound/blob/master/phrakture) 11 | # Note: there is also a slightly modified (earlier?) version (also called rezza) which can be found here: 12 | # https://sheet.shiar.nl/source/data/termcol-xcolor.inc.pl 13 | # and also posted here: 14 | # https://forums.debian.net/viewtopic.php?t=29981 15 | 16 | [colors] 17 | foreground = cccccc 18 | background = 191911 19 | 20 | # Normal colors 21 | regular0 = 222222 22 | regular1 = 803232 23 | regular2 = 5b762f 24 | regular3 = aa9943 25 | regular4 = 324c80 26 | regular5 = 706c9a 27 | regular6 = 92b19e 28 | regular7 = ffffff 29 | 30 | # Bright colors 31 | bright0 = 222222 32 | bright1 = 982b2b 33 | bright2 = 89b83f 34 | bright3 = efef60 35 | bright4 = 2b4f98 36 | bright5 = 826ab1 37 | bright6 = a1cdcd 38 | bright7 = dedede 39 | -------------------------------------------------------------------------------- /themes/rose-pine: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Rose-Piné 3 | 4 | [cursor] 5 | color=191724 e0def4 6 | 7 | [colors] 8 | background=191724 9 | foreground=e0def4 10 | regular0=26233a # black 11 | regular1=eb6f92 # red 12 | regular2=31748f # green 13 | regular3=f6c177 # yellow 14 | regular4=9ccfd8 # blue 15 | regular5=c4a7e7 # magenta 16 | regular6=ebbcba # cyan 17 | regular7=e0def4 # white 18 | 19 | bright0=6e6a86 # bright black 20 | bright1=eb6f92 # bright red 21 | bright2=31748f # bright green 22 | bright3=f6c177 # bright yellow 23 | bright4=9ccfd8 # bright blue 24 | bright5=c4a7e7 # bright magenta 25 | bright6=ebbcba # bright cyan 26 | bright7=e0def4 # bright white -------------------------------------------------------------------------------- /themes/selenized-black: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Selenized black 3 | 4 | [cursor] 5 | color = 181818 56d8c9 6 | 7 | [colors] 8 | background= 181818 9 | foreground= b9b9b9 10 | 11 | regular0= 252525 12 | regular1= ed4a46 13 | regular2= 70b433 14 | regular3= dbb32d 15 | regular4= 368aeb 16 | regular5= eb6eb7 17 | regular6= 3fc5b7 18 | regular7= 777777 19 | 20 | bright0= 3b3b3b 21 | bright1= ff5e56 22 | bright2= 83c746 23 | bright3= efc541 24 | bright4= 4f9cfe 25 | bright5= ff81ca 26 | bright6= 56d8c9 27 | bright7= dedede 28 | -------------------------------------------------------------------------------- /themes/selenized-dark: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Selenized dark 3 | 4 | [cursor] 5 | color = 103c48 53d6c7 6 | 7 | [colors] 8 | background= 103c48 9 | foreground= adbcbc 10 | 11 | regular0= 184956 12 | regular1= fa5750 13 | regular2= 75b938 14 | regular3= dbb32d 15 | regular4= 4695f7 16 | regular5= f275be 17 | regular6= 41c7b9 18 | regular7= 72898f 19 | 20 | bright0= 2d5b69 21 | bright1= ff665c 22 | bright2= 84c747 23 | bright3= ebc13d 24 | bright4= 58a3ff 25 | bright5= ff84cd 26 | bright6= 53d6c7 27 | bright7= cad8d9 28 | -------------------------------------------------------------------------------- /themes/selenized-light: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Selenized light 3 | 4 | [cursor] 5 | color=fbf3db 00978a 6 | 7 | [colors] 8 | background= fbf3db 9 | foreground= 53676d 10 | 11 | regular0= ece3cc 12 | regular1= d2212d 13 | regular2= 489100 14 | regular3= ad8900 15 | regular4= 0072d4 16 | regular5= ca4898 17 | regular6= 009c8f 18 | regular7= 909995 19 | 20 | bright0= d5cdb6 21 | bright1= cc1729 22 | bright2= 428b00 23 | bright3= a78300 24 | bright4= 006dce 25 | bright5= c44392 26 | bright6= 00978a 27 | bright7= 3a4d53 28 | -------------------------------------------------------------------------------- /themes/selenized-white: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Selenized white 3 | 4 | [cursor] 5 | color=ffffff 009a8a 6 | 7 | [colors] 8 | background= ffffff 9 | foreground= 474747 10 | 11 | regular0= ebebeb 12 | regular1= d6000c 13 | regular2= 1d9700 14 | regular3= c49700 15 | regular4= 0064e4 16 | regular5= dd0f9d 17 | regular6= 00ad9c 18 | regular7= 878787 19 | 20 | bright0= cdcdcd 21 | bright1= bf0000 22 | bright2= 008400 23 | bright3= af8500 24 | bright4= 0054cf 25 | bright5= c7008b 26 | bright6= 009a8a 27 | bright7= 282828 28 | -------------------------------------------------------------------------------- /themes/solarized-dark: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Solarized dark 3 | 4 | [cursor] 5 | color= 002b36 93a1a1 6 | 7 | [colors] 8 | background= 002b36 9 | foreground= 839496 10 | regular0= 073642 11 | regular1= dc322f 12 | regular2= 859900 13 | regular3= b58900 14 | regular4= 268bd2 15 | regular5= d33682 16 | regular6= 2aa198 17 | regular7= eee8d5 18 | bright0= 002b36 19 | bright1= cb4b16 20 | bright2= 586e75 21 | bright3= 657b83 22 | bright4= 839496 23 | bright5= 6c71c4 24 | bright6= 93a1a1 25 | bright7= fdf6e3 26 | 27 | # Enable if prefer solarized colors instead of inverterd fg/bg for 28 | # highlighting (mouse selection) 29 | # selection-foreground=93a1a1 30 | # selection-background=073642 31 | -------------------------------------------------------------------------------- /themes/solarized-dark-normal-brights: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Solarized dark 3 | 4 | [cursor] 5 | color= 002b36 93a1a1 6 | 7 | [colors] 8 | background= 002b36 9 | foreground= 839496 10 | regular0= 073642 11 | regular1= dc322f 12 | regular2= 859900 13 | regular3= b58900 14 | regular4= 268bd2 15 | regular5= d33682 16 | regular6= 2aa198 17 | regular7= eee8d5 18 | 19 | # regularN brightened by increasing luminance by 20% 20 | bright0= 08404f 21 | bright1= e35f5c 22 | bright2= 9fb700 23 | bright3= d9a400 24 | bright4= 4ba1de 25 | bright5= dc619d 26 | bright6= 32c1b6 27 | bright7= ffffff 28 | 29 | # Enable if prefer solarized colors instead of inverterd fg/bg for 30 | # highlighting (mouse selection) 31 | # selection-foreground=93a1a1 32 | # selection-background=073642 33 | -------------------------------------------------------------------------------- /themes/solarized-light: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Solarized light 3 | 4 | [cursor] 5 | color=fdf6e3 586e75 6 | 7 | [colors] 8 | background= fdf6e3 9 | foreground= 657b83 10 | regular0= eee8d5 11 | regular1= dc322f 12 | regular2= 859900 13 | regular3= b58900 14 | regular4= 268bd2 15 | regular5= d33682 16 | regular6= 2aa198 17 | regular7= 073642 18 | bright0= cb4b16 19 | bright1= fdf6e3 20 | bright2= 93a1a1 21 | bright3= 839496 22 | bright4= 657b83 23 | bright5= 6c71c4 24 | bright6= 586e75 25 | bright7= 002b36 26 | -------------------------------------------------------------------------------- /themes/srcery: -------------------------------------------------------------------------------- 1 | # srcery 2 | 3 | [colors] 4 | background= 1c1b19 5 | foreground= fce8c3 6 | regular0= 1c1b19 7 | regular1= ef2f27 8 | regular2= 519f50 9 | regular3= fbb829 10 | regular4= 2c78bf 11 | regular5= e02c6d 12 | regular6= 0aaeb3 13 | regular7= baa67f 14 | bright0= 918175 15 | bright1= f75341 16 | bright2= 98bc37 17 | bright3= fed06e 18 | bright4= 68a8e4 19 | bright5= ff5c8f 20 | bright6= 2be4d0 21 | bright7= fce8c3 22 | 23 | ## Enable if prefer solarized colors instead of inverterd fg/bg for 24 | ## highlighting (mouse selection) 25 | # selection-foreground=93a1a1 26 | # selection-background=073642 27 | -------------------------------------------------------------------------------- /themes/starlight: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Theme: starlight V4 (https://github.com/CosmicToast/starlight) 3 | 4 | [colors] 5 | foreground = FFFFFF 6 | background = 242424 7 | 8 | regular0 = 242424 9 | regular1 = f62b5a 10 | regular2 = 47b413 11 | regular3 = e3c401 12 | regular4 = 24acd4 13 | regular5 = f2affd 14 | regular6 = 13c299 15 | regular7 = e6e6e6 16 | 17 | bright0 = 616161 18 | bright1 = ff4d51 19 | bright2 = 35d450 20 | bright3 = e9e836 21 | bright4 = 5dc5f8 22 | bright5 = feabf2 23 | bright6 = 24dfc4 24 | bright7 = ffffff 25 | -------------------------------------------------------------------------------- /themes/tango: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Tango 3 | 4 | [cursor] 5 | color=000000 babdb6 6 | 7 | [colors] 8 | foreground=babdb6 9 | background=000000 10 | regular0=2e3436 11 | regular1=cc0000 12 | regular2=4e9a06 13 | regular3=c4a000 14 | regular4=3465a4 15 | regular5=75507b 16 | regular6=06989a 17 | regular7=d3d7cf 18 | bright0=555753 19 | bright1=ef2929 20 | bright2=8ae234 21 | bright3=fce94f 22 | bright4=729fcf 23 | bright5=ad7fa8 24 | bright6=34e2e2 25 | bright7=eeeeec 26 | -------------------------------------------------------------------------------- /themes/tempus-autumn: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Autumn 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Dark theme with a palette inspired by earthly colours (WCAG AA compliant) 5 | 6 | #[cursor] 7 | #color = 302420 a9a2a6 8 | 9 | [colors] 10 | foreground = a9a2a6 11 | background = 302420 12 | regular0 = 302420 13 | regular1 = f46f55 14 | regular2 = 85a400 15 | regular3 = b09640 16 | regular4 = 799aca 17 | regular5 = df798e 18 | regular6 = 52a885 19 | regular7 = a8948a 20 | bright0 = 36302a 21 | bright1 = e27e3d 22 | bright2 = 43aa7a 23 | bright3 = ba9400 24 | bright4 = 958fdf 25 | bright5 = ce7dc4 26 | bright6 = 2fa6b7 27 | bright7 = a9a2a6 28 | # selection-foreground = a8948a 29 | # selection-background = 36302a 30 | -------------------------------------------------------------------------------- /themes/tempus-classic: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Classic 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Dark theme with warm hues (WCAG AA compliant) 5 | 6 | #[cursor] 7 | #color = 232323 aeadaf 8 | 9 | [colors] 10 | foreground = aeadaf 11 | background = 232323 12 | regular0 = 232323 13 | regular1 = d4823d 14 | regular2 = 8c9e3d 15 | regular3 = b1942b 16 | regular4 = 6e9cb0 17 | regular5 = b58d88 18 | regular6 = 6da280 19 | regular7 = 949d9f 20 | bright0 = 312e30 21 | bright1 = d0913d 22 | bright2 = 96a42d 23 | bright3 = a8a030 24 | bright4 = 8e9cc0 25 | bright5 = d58888 26 | bright6 = 7aa880 27 | bright7 = aeadaf 28 | # selection-foreground = 949d9f 29 | # selection-background = 312e30 30 | -------------------------------------------------------------------------------- /themes/tempus-dawn: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Dawn 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Light theme with a soft, slightly desaturated palette (WCAG AA compliant) 5 | 6 | #[cursor] 7 | #color = eff0f2 4a4b4e 8 | 9 | [colors] 10 | foreground = 4a4b4e 11 | background = eff0f2 12 | regular0 = 4a4b4e 13 | regular1 = a32a3a 14 | regular2 = 206620 15 | regular3 = 745300 16 | regular4 = 4b529a 17 | regular5 = 8d377e 18 | regular6 = 086784 19 | regular7 = dee2e0 20 | bright0 = 676364 21 | bright1 = a64822 22 | bright2 = 187408 23 | bright3 = 8b590a 24 | bright4 = 5c59b2 25 | bright5 = 8e45a8 26 | bright6 = 3f649c 27 | bright7 = eff0f2 28 | # selection-foreground = 676364 29 | # selection-background = dee2e0 30 | -------------------------------------------------------------------------------- /themes/tempus-day: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Day 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Light theme with warm colours (WCAG AA compliant) 5 | 6 | #[cursor] 7 | #color = f8f2e5 464340 8 | 9 | [colors] 10 | foreground = 464340 11 | background = f8f2e5 12 | regular0 = 464340 13 | regular1 = c81000 14 | regular2 = 107410 15 | regular3 = 806000 16 | regular4 = 385dc4 17 | regular5 = b63052 18 | regular6 = 007070 19 | regular7 = e7e3d7 20 | bright0 = 68607d 21 | bright1 = b24000 22 | bright2 = 427040 23 | bright3 = 6f6600 24 | bright4 = 0f64c4 25 | bright5 = 8050a7 26 | bright6 = 336c87 27 | bright7 = f8f2e5 28 | # selection-foreground = 68607d 29 | # selection-background = e7e3d7 30 | -------------------------------------------------------------------------------- /themes/tempus-dusk: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Dusk 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Dark theme with a deep blue-ish, slightly desaturated palette (WCAG AA compliant) 5 | 6 | #[cursor] 7 | #color = 1f252d a2a8ba 8 | 9 | [colors] 10 | foreground = a2a8ba 11 | background = 1f252d 12 | regular0 = 1f252d 13 | regular1 = cb8d56 14 | regular2 = 8ba089 15 | regular3 = a79c46 16 | regular4 = 8c9abe 17 | regular5 = b190af 18 | regular6 = 8e9aba 19 | regular7 = a29899 20 | bright0 = 2c3150 21 | bright1 = d39d74 22 | bright2 = 80b48f 23 | bright3 = bda75a 24 | bright4 = 9ca5de 25 | bright5 = c69ac6 26 | bright6 = 8caeb6 27 | bright7 = a2a8ba 28 | # selection-foreground = a29899 29 | # selection-background = 2c3150 30 | -------------------------------------------------------------------------------- /themes/tempus-fugit: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Fugit 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Light, pleasant theme optimised for long writing/coding sessions (WCAG AA compliant) 5 | 6 | #[cursor] 7 | #color = fff5f3 4d595f 8 | 9 | [colors] 10 | foreground = 4d595f 11 | background = fff5f3 12 | regular0 = 4d595f 13 | regular1 = c61a14 14 | regular2 = 357200 15 | regular3 = 825e00 16 | regular4 = 1666b0 17 | regular5 = a83884 18 | regular6 = 007072 19 | regular7 = efe6e4 20 | bright0 = 796271 21 | bright1 = b93f1a 22 | bright2 = 437520 23 | bright3 = 985900 24 | bright4 = 485adf 25 | bright5 = a234c0 26 | bright6 = 00756a 27 | bright7 = fff5f3 28 | # selection-foreground = 796271 29 | # selection-background = efe6e4 30 | -------------------------------------------------------------------------------- /themes/tempus-future: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Future 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Dark theme with colours inspired by concept art of outer space (WCAG AAA compliant) 5 | 6 | #[cursor] 7 | #color = 090a18 b4abac 8 | 9 | [colors] 10 | foreground = b4abac 11 | background = 090a18 12 | regular0 = 090a18 13 | regular1 = ff7e8f 14 | regular2 = 6aba39 15 | regular3 = bfa51a 16 | regular4 = 4ab2d7 17 | regular5 = e58f84 18 | regular6 = 2ab7bb 19 | regular7 = a7a2c4 20 | bright0 = 2b1329 21 | bright1 = f78e2f 22 | bright2 = 60ba80 23 | bright3 = de9b1d 24 | bright4 = 8ba7ea 25 | bright5 = e08bd6 26 | bright6 = 2cbab6 27 | bright7 = b4abac 28 | # selection-foreground = a7a2c4 29 | # selection-background = 2b1329 30 | -------------------------------------------------------------------------------- /themes/tempus-night: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Night 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: High contrast dark theme with bright colours (WCAG AAA compliant) 5 | 6 | #[cursor] 7 | #color = 1a1a1a e0e0e0 8 | 9 | [colors] 10 | foreground = e0e0e0 11 | background = 1a1a1a 12 | regular0 = 1a1a1a 13 | regular1 = ff929f 14 | regular2 = 5fc940 15 | regular3 = c5b300 16 | regular4 = 5fb8ff 17 | regular5 = ef91df 18 | regular6 = 1dc5c3 19 | regular7 = c4bdaf 20 | bright0 = 242536 21 | bright1 = f69d6a 22 | bright2 = 88c400 23 | bright3 = d7ae00 24 | bright4 = 8cb4f0 25 | bright5 = de99f0 26 | bright6 = 00ca9a 27 | bright7 = e0e0e0 28 | # selection-foreground = c4bdaf 29 | # selection-background = 242536 30 | -------------------------------------------------------------------------------- /themes/tempus-past: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Past 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Light theme inspired by old vaporwave concept art (WCAG AA compliant) 5 | 6 | #[cursor] 7 | #color = f3f2f4 53545b 8 | 9 | [colors] 10 | foreground = 53545b 11 | background = f3f2f4 12 | regular0 = 53545b 13 | regular1 = c00c50 14 | regular2 = 0a7040 15 | regular3 = a6403a 16 | regular4 = 1763aa 17 | regular5 = b02874 18 | regular6 = 096a83 19 | regular7 = eae2de 20 | bright0 = 80565d 21 | bright1 = bd3133 22 | bright2 = 337243 23 | bright3 = 8d554a 24 | bright4 = 5559bb 25 | bright5 = b022a7 26 | bright6 = 07707a 27 | bright7 = f3f2f4 28 | # selection-foreground = 80565d 29 | # selection-background = eae2de 30 | -------------------------------------------------------------------------------- /themes/tempus-rift: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Rift 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Dark theme with a subdued palette on the green side of the spectrum (WCAG AA compliant) 5 | 6 | #[cursor] 7 | #color = 162c22 bbbcbc 8 | 9 | [colors] 10 | foreground = bbbcbc 11 | background = 162c22 12 | regular0 = 162c22 13 | regular1 = c19904 14 | regular2 = 34b534 15 | regular3 = 7fad00 16 | regular4 = 30aeb0 17 | regular5 = c8954c 18 | regular6 = 5fad8f 19 | regular7 = ab9aa9 20 | bright0 = 283431 21 | bright1 = d2a634 22 | bright2 = 6ac134 23 | bright3 = 82bd00 24 | bright4 = 56bdad 25 | bright5 = cca0ba 26 | bright6 = 10c480 27 | bright7 = bbbcbc 28 | # selection-foreground = ab9aa9 29 | # selection-background = 283431 30 | -------------------------------------------------------------------------------- /themes/tempus-spring: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Spring 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Dark theme with a palette inspired by early spring colours (WCAG AA compliant) 5 | 6 | #[cursor] 7 | #color = 283a37 b5b8b7 8 | 9 | [colors] 10 | foreground = b5b8b7 11 | background = 283a37 12 | regular0 = 283a37 13 | regular1 = ff8b5f 14 | regular2 = 5ec04d 15 | regular3 = b0b01a 16 | regular4 = 39bace 17 | regular5 = e99399 18 | regular6 = 36c08e 19 | regular7 = 99afae 20 | bright0 = 2a453d 21 | bright1 = e19e00 22 | bright2 = 73be0d 23 | bright3 = c6a843 24 | bright4 = 70afef 25 | bright5 = d095e2 26 | bright6 = 3cbfaf 27 | bright7 = b5b8b7 28 | # selection-foreground = 99afae 29 | # selection-background = 2a453d 30 | -------------------------------------------------------------------------------- /themes/tempus-summer: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Summer 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Dark theme with colours inspired by summer evenings by the sea (WCAG AA compliant) 5 | 6 | #[cursor] 7 | #color = 202c3d a0abae 8 | 9 | [colors] 10 | foreground = a0abae 11 | background = 202c3d 12 | regular0 = 202c3d 13 | regular1 = fe6f70 14 | regular2 = 4eb075 15 | regular3 = ba9a0a 16 | regular4 = 60a1e6 17 | regular5 = d285ad 18 | regular6 = 3dae9f 19 | regular7 = 949cbf 20 | bright0 = 39304f 21 | bright1 = ec7f4f 22 | bright2 = 5baf4f 23 | bright3 = be981f 24 | bright4 = 8599ef 25 | bright5 = cc82d7 26 | bright6 = 2aacbf 27 | bright7 = a0abae 28 | # selection-foreground = 949cbf 29 | # selection-background = 39304f 30 | -------------------------------------------------------------------------------- /themes/tempus-tempest: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Tempest 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: A green-scale, subtle theme for late night hackers (WCAG AAA compliant) 5 | 6 | #[cursor] 7 | #color = 282b2b b6e0ca 8 | 9 | [colors] 10 | foreground = b6e0ca 11 | background = 282b2b 12 | regular0 = 282b2b 13 | regular1 = cfc80a 14 | regular2 = 7ad97a 15 | regular3 = bfcc4a 16 | regular4 = 60d7cd 17 | regular5 = c5c4af 18 | regular6 = 8bd0bf 19 | regular7 = b0c8ca 20 | bright0 = 323535 21 | bright1 = d1d933 22 | bright2 = 99e299 23 | bright3 = bbde4f 24 | bright4 = 74e4cd 25 | bright5 = d2d4aa 26 | bright6 = 9bdfc4 27 | bright7 = b6e0ca 28 | # selection-foreground = b0c8ca 29 | # selection-background = 323535 30 | -------------------------------------------------------------------------------- /themes/tempus-totus: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Totus 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Light theme for prose or for coding in an open space (WCAG AAA compliant) 5 | 6 | #[cursor] 7 | #color = ffffff 4a484d 8 | 9 | [colors] 10 | foreground = 4a484d 11 | background = ffffff 12 | regular0 = 4a484d 13 | regular1 = a50000 14 | regular2 = 005d26 15 | regular3 = 714700 16 | regular4 = 1d3ccf 17 | regular5 = 88267a 18 | regular6 = 185570 19 | regular7 = efefef 20 | bright0 = 5e4b4f 21 | bright1 = 992030 22 | bright2 = 4a5500 23 | bright3 = 8a3600 24 | bright4 = 2d45b0 25 | bright5 = 700dc9 26 | bright6 = 005289 27 | bright7 = ffffff 28 | # selection-foreground = 5e4b4f 29 | # selection-background = efefef 30 | -------------------------------------------------------------------------------- /themes/tempus-warp: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Warp 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Dark theme with a vibrant palette (WCAG AA compliant) 5 | 6 | #[cursor] 7 | #color = 001514 a29fa0 8 | 9 | [colors] 10 | foreground = a29fa0 11 | background = 001514 12 | regular0 = 001514 13 | regular1 = ff3737 14 | regular2 = 169c16 15 | regular3 = 9f8500 16 | regular4 = 5781ef 17 | regular5 = da4ebf 18 | regular6 = 009880 19 | regular7 = 968282 20 | bright0 = 261c2c 21 | bright1 = F0681A 22 | bright2 = 3aa73a 23 | bright3 = ba8a00 24 | bright4 = 8887f0 25 | bright5 = d85cf2 26 | bright6 = 1da1af 27 | bright7 = a29fa0 28 | # selection-foreground = 968282 29 | # selection-background = 261c2c 30 | -------------------------------------------------------------------------------- /themes/tempus-winter: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # theme: Tempus Winter 3 | # author: Protesilaos Stavrou (https://protesilaos.com) 4 | # description: Dark theme with a palette inspired by winter nights at the city (WCAG AA compliant) 5 | 6 | #[cursor] 7 | #color = 202427 8da3b8 8 | 9 | [colors] 10 | foreground = 8da3b8 11 | background = 202427 12 | regular0 = 202427 13 | regular1 = ed6e5a 14 | regular2 = 4aa920 15 | regular3 = 9a9921 16 | regular4 = 7b91df 17 | regular5 = d17e80 18 | regular6 = 4fa394 19 | regular7 = 91959b 20 | bright0 = 2a2e38 21 | bright1 = de7b28 22 | bright2 = 00ab5f 23 | bright3 = af9155 24 | bright4 = 329fcb 25 | bright5 = ca77c5 26 | bright6 = 1ba6a4 27 | bright7 = 8da3b8 28 | # selection-foreground = 91959b 29 | # selection-background = 2a2e38 30 | -------------------------------------------------------------------------------- /themes/tokyonight-day: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | 3 | [colors] 4 | background=e1e2e7 5 | foreground=3760bf 6 | regular0=e9e9ed 7 | regular1=f52a65 8 | regular2=587539 9 | regular3=8c6c3e 10 | regular4=2e7de9 11 | regular5=9854f1 12 | regular6=007197 13 | regular7=6172b0 14 | bright0=a1a6c5 15 | bright1=f52a65 16 | bright2=587539 17 | bright3=8c6c3e 18 | bright4=2e7de9 19 | bright5=9854f1 20 | bright6=007197 21 | bright7=3760bf -------------------------------------------------------------------------------- /themes/tokyonight-night: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | 3 | [colors] 4 | background=1a1b26 5 | foreground=c0caf5 6 | regular0=15161E 7 | regular1=f7768e 8 | regular2=9ece6a 9 | regular3=e0af68 10 | regular4=7aa2f7 11 | regular5=bb9af7 12 | regular6=7dcfff 13 | regular7=a9b1d6 14 | bright0=414868 15 | bright1=f7768e 16 | bright2=9ece6a 17 | bright3=e0af68 18 | bright4=7aa2f7 19 | bright5=bb9af7 20 | bright6=7dcfff 21 | bright7=c0caf5 22 | -------------------------------------------------------------------------------- /themes/tokyonight-storm: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | 3 | [colors] 4 | background=24283b 5 | foreground=c0caf5 6 | regular0=1D202F 7 | regular1=f7768e 8 | regular2=9ece6a 9 | regular3=e0af68 10 | regular4=7aa2f7 11 | regular5=bb9af7 12 | regular6=7dcfff 13 | regular7=a9b1d6 14 | bright0=414868 15 | bright1=f7768e 16 | bright2=9ece6a 17 | bright3=e0af68 18 | bright4=7aa2f7 19 | bright5=bb9af7 20 | bright6=7dcfff 21 | bright7=c0caf5 22 | -------------------------------------------------------------------------------- /themes/visibone: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # VisiBone 3 | 4 | [cursor] 5 | color=010101 ffffff 6 | 7 | [colors] 8 | foreground=ffffff 9 | background=010101 10 | regular0=666666 11 | regular1=cc6666 12 | regular2=66cc99 13 | regular3=cc9966 14 | regular4=6699cc 15 | regular5=cc6699 16 | regular6=66cccc 17 | regular7=cccccc 18 | bright0=999999 19 | bright1=ff9999 20 | bright2=99ffcc 21 | bright3=ffcc99 22 | bright4=99ccff 23 | bright5=ff99cc 24 | bright6=99ffff 25 | bright7=ffffff 26 | -------------------------------------------------------------------------------- /themes/xterm: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # The default palette of xterm. 3 | 4 | [colors] 5 | foreground=e5e5e5 6 | background=000000 7 | regular0=000000 # black 8 | regular1=cd0000 # red 9 | regular2=00cd00 # green 10 | regular3=cdcd00 # yellow 11 | regular4=0000ee # blue 12 | regular5=cd00cd # magenta 13 | regular6=00cdcd # cyan 14 | regular7=e5e5e5 # white 15 | bright0=7f7f7f # bright black 16 | bright1=ff0000 # bright red 17 | bright2=00ff00 # bright green 18 | bright3=ffff00 # bright yellow 19 | bright4=5c5cff # bright blue 20 | bright5=ff00ff # bright magenta 21 | bright6=00ffff # bright cyan 22 | bright7=ffffff # bright white 23 | -------------------------------------------------------------------------------- /themes/zenburn: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | 3 | [colors] 4 | foreground=dcdccc 5 | background=111111 6 | 7 | ## Normal/regular colors (color palette 0-7) 8 | regular0=222222 # black 9 | regular1=cc9393 # red 10 | regular2=7f9f7f # green 11 | regular3=d0bf8f # yellow 12 | regular4=6ca0a3 # blue 13 | regular5=dc8cc3 # magenta 14 | regular6=93e0e3 # cyan 15 | regular7=dcdccc # white 16 | 17 | ## Bright colors (color palette 8-15) 18 | bright0=666666 # bright black 19 | bright1=dca3a3 # bright red 20 | bright2=bfebbf # bright green 21 | bright3=f0dfaf # bright yellow 22 | bright4=8cd0d3 # bright blue 23 | bright5=fcace3 # bright magenta 24 | bright6=b3ffff # bright cyan 25 | bright7=ffffff # bright white 26 | -------------------------------------------------------------------------------- /tokenize.c: -------------------------------------------------------------------------------- 1 | #include "tokenize.h" 2 | 3 | #include 4 | #include 5 | 6 | #define LOG_MODULE "tokenize" 7 | #define LOG_ENABLE_DBG 0 8 | #include "log.h" 9 | #include "xmalloc.h" 10 | 11 | static bool 12 | push_argv(char ***argv, size_t *size, const char *arg, size_t len, size_t *argc) 13 | { 14 | if (arg != NULL && arg[0] == '%') 15 | return true; 16 | 17 | if (*argc >= *size) { 18 | size_t new_size = *size > 0 ? 2 * *size : 10; 19 | char **new_argv = realloc(*argv, new_size * sizeof(new_argv[0])); 20 | 21 | if (new_argv == NULL) 22 | return false; 23 | 24 | *argv = new_argv; 25 | *size = new_size; 26 | } 27 | 28 | (*argv)[(*argc)++] = arg != NULL ? xstrndup(arg, len) : NULL; 29 | return true; 30 | } 31 | 32 | bool 33 | tokenize_cmdline(const char *cmdline, char ***argv) 34 | { 35 | *argv = NULL; 36 | size_t argv_size = 0; 37 | 38 | const char *final_end = cmdline + strlen(cmdline) + 1; 39 | 40 | bool first_token_is_quoted = cmdline[0] == '"' || cmdline[0] == '\''; 41 | char delim = first_token_is_quoted ? cmdline[0] : ' '; 42 | 43 | const char *p = first_token_is_quoted ? &cmdline[1] : &cmdline[0]; 44 | const char *search_start = p; 45 | 46 | size_t idx = 0; 47 | while (*p != '\0') { 48 | char *end = strchr(search_start, delim); 49 | if (end == NULL) { 50 | if (delim != ' ') { 51 | LOG_ERR("unterminated %s quote", delim == '"' ? "double" : "single"); 52 | goto err; 53 | } 54 | 55 | if (!push_argv(argv, &argv_size, p, final_end - p, &idx) || 56 | !push_argv(argv, &argv_size, NULL, 0, &idx)) 57 | { 58 | goto err; 59 | } else 60 | return true; 61 | } 62 | 63 | if (end > p && *(end - 1) == '\\') { 64 | /* Escaped quote, remove one level of escaping and 65 | * continue searching for "our" closing quote */ 66 | memmove(end - 1, end, strlen(end)); 67 | end[strlen(end) - 1] = '\0'; 68 | search_start = end; 69 | continue; 70 | } 71 | 72 | //*end = '\0'; 73 | 74 | if (!push_argv(argv, &argv_size, p, end - p, &idx)) 75 | goto err; 76 | 77 | p = end + 1; 78 | while (*p == delim) 79 | p++; 80 | 81 | while (*p == ' ') 82 | p++; 83 | 84 | if (*p == '"' || *p == '\'') { 85 | delim = *p; 86 | p++; 87 | } else 88 | delim = ' '; 89 | search_start = p; 90 | } 91 | 92 | if (!push_argv(argv, &argv_size, NULL, 0, &idx)) 93 | goto err; 94 | 95 | return true; 96 | 97 | err: 98 | for (size_t i = 0; i < idx; i++) 99 | free((*argv)[i]); 100 | free(*argv); 101 | *argv = NULL; 102 | return false; 103 | } 104 | -------------------------------------------------------------------------------- /tokenize.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | bool tokenize_cmdline(const char *cmdline, char ***argv); 6 | -------------------------------------------------------------------------------- /unicode-mode.c: -------------------------------------------------------------------------------- 1 | #include "unicode-mode.h" 2 | 3 | #define LOG_MODULE "unicode-input" 4 | #define LOG_ENABLE_DBG 0 5 | #include "log.h" 6 | #include "render.h" 7 | #include "search.h" 8 | 9 | void 10 | unicode_mode_activate(struct terminal *term) 11 | { 12 | if (term->unicode_mode.active) 13 | return; 14 | 15 | term->unicode_mode.active = true; 16 | term->unicode_mode.character = u'\0'; 17 | term->unicode_mode.count = 0; 18 | unicode_mode_updated(term); 19 | } 20 | 21 | void 22 | unicode_mode_deactivate(struct terminal *term) 23 | { 24 | if (!term->unicode_mode.active) 25 | return; 26 | 27 | term->unicode_mode.active = false; 28 | unicode_mode_updated(term); 29 | } 30 | 31 | void 32 | unicode_mode_updated(struct terminal *term) 33 | { 34 | if (term == NULL) 35 | return; 36 | 37 | if (term->is_searching) 38 | render_refresh_search(term); 39 | else 40 | render_refresh(term); 41 | } 42 | 43 | void 44 | unicode_mode_input(struct seat *seat, struct terminal *term, 45 | xkb_keysym_t sym) 46 | { 47 | if (sym == XKB_KEY_Return || 48 | sym == XKB_KEY_space || 49 | sym == XKB_KEY_KP_Enter || 50 | sym == XKB_KEY_KP_Space) 51 | { 52 | char utf8[MB_CUR_MAX]; 53 | size_t chars = c32rtomb( 54 | utf8, term->unicode_mode.character, &(mbstate_t){0}); 55 | 56 | LOG_DBG("Unicode input: 0x%06x -> %.*s", 57 | term->unicode_mode.character, (int)chars, utf8); 58 | 59 | if (chars != (size_t)-1) { 60 | if (term->is_searching) 61 | search_add_chars(term, utf8, chars); 62 | else 63 | term_to_slave(term, utf8, chars); 64 | } 65 | 66 | unicode_mode_deactivate(term); 67 | } 68 | 69 | else if (sym == XKB_KEY_Escape || 70 | sym == XKB_KEY_q || 71 | (seat->kbd.ctrl && (sym == XKB_KEY_c || 72 | sym == XKB_KEY_d || 73 | sym == XKB_KEY_g))) 74 | { 75 | unicode_mode_deactivate(term); 76 | } 77 | 78 | else if (sym == XKB_KEY_BackSpace) { 79 | if (term->unicode_mode.count > 0) { 80 | term->unicode_mode.character >>= 4; 81 | term->unicode_mode.count--; 82 | unicode_mode_updated(term); 83 | } 84 | } 85 | 86 | else if (term->unicode_mode.count < 6) { 87 | int digit = -1; 88 | 89 | /* 0-9, a-f, A-F */ 90 | if (sym >= XKB_KEY_0 && sym <= XKB_KEY_9) 91 | digit = sym - XKB_KEY_0; 92 | else if (sym >= XKB_KEY_KP_0 && sym <= XKB_KEY_KP_9) 93 | digit = sym - XKB_KEY_KP_0; 94 | else if (sym >= XKB_KEY_a && sym <= XKB_KEY_f) 95 | digit = 0xa + (sym - XKB_KEY_a); 96 | else if (sym >= XKB_KEY_A && sym <= XKB_KEY_F) 97 | digit = 0xa + (sym - XKB_KEY_A); 98 | 99 | if (digit >= 0) { 100 | xassert(digit >= 0 && digit <= 0xf); 101 | term->unicode_mode.character <<= 4; 102 | term->unicode_mode.character |= digit; 103 | term->unicode_mode.count++; 104 | unicode_mode_updated(term); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /unicode-mode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "terminal.h" 6 | 7 | void unicode_mode_activate(struct terminal *term); 8 | void unicode_mode_deactivate(struct terminal *term); 9 | void unicode_mode_updated(struct terminal *term); 10 | void unicode_mode_input(struct seat *seat, struct terminal *term, 11 | xkb_keysym_t sym); 12 | -------------------------------------------------------------------------------- /uri.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | bool uri_parse(const char *uri, size_t len, 8 | char **scheme, char **user, char **password, char **host, 9 | uint16_t *port, char **path, char **query, char **fragment); 10 | 11 | bool hostname_is_localhost(const char *hostname); 12 | -------------------------------------------------------------------------------- /url-mode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "config.h" 8 | #include "key-binding.h" 9 | #include "terminal.h" 10 | 11 | static inline bool urls_mode_is_active(const struct terminal *term) 12 | { 13 | return tll_length(term->urls) > 0; 14 | } 15 | 16 | void urls_collect( 17 | const struct terminal *term, enum url_action action, url_list_t *urls); 18 | void urls_assign_key_combos(const struct config *conf, url_list_t *urls); 19 | 20 | void urls_render(struct terminal *term); 21 | void urls_reset(struct terminal *term); 22 | 23 | void urls_input(struct seat *seat, struct terminal *term, 24 | const struct key_binding_set *bindings, uint32_t key, 25 | xkb_keysym_t sym, xkb_mod_mask_t mods, xkb_mod_mask_t consumed, 26 | const xkb_keysym_t *raw_syms, size_t raw_count, 27 | uint32_t serial); 28 | -------------------------------------------------------------------------------- /user-notification.c: -------------------------------------------------------------------------------- 1 | #include "user-notification.h" 2 | #include 3 | #include "xmalloc.h" 4 | 5 | void 6 | user_notification_add_fmt(user_notifications_t *notifications, 7 | enum user_notification_kind kind, const char *fmt, ...) 8 | { 9 | va_list ap; 10 | va_start(ap, fmt); 11 | char *text = xvasprintf(fmt, ap); 12 | va_end(ap); 13 | user_notification_add(notifications, kind, text); 14 | } 15 | -------------------------------------------------------------------------------- /user-notification.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "macros.h" 6 | 7 | enum user_notification_kind { 8 | USER_NOTIFICATION_DEPRECATED, 9 | USER_NOTIFICATION_WARNING, 10 | USER_NOTIFICATION_ERROR, 11 | }; 12 | 13 | struct user_notification { 14 | enum user_notification_kind kind; 15 | char *text; 16 | }; 17 | 18 | typedef tll(struct user_notification) user_notifications_t; 19 | 20 | static inline void 21 | user_notifications_free(user_notifications_t *notifications) 22 | { 23 | tll_foreach(*notifications, it) 24 | free(it->item.text); 25 | tll_free(*notifications); 26 | } 27 | 28 | static inline void 29 | user_notification_add(user_notifications_t *notifications, 30 | enum user_notification_kind kind, char *text) 31 | { 32 | struct user_notification notification = { 33 | .kind = kind, 34 | .text = text 35 | }; 36 | tll_push_back(*notifications, notification); 37 | } 38 | 39 | void user_notification_add_fmt(user_notifications_t *notifications, 40 | enum user_notification_kind kind, 41 | const char *fmt, ...) PRINTF(3); 42 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define ALEN(v) (sizeof(v) / sizeof((v)[0])) 9 | #define min(x, y) ((x) < (y) ? (x) : (y)) 10 | #define max(x, y) ((x) > (y) ? (x) : (y)) 11 | 12 | static inline bool 13 | streq(const char *a, const char *b) 14 | { 15 | return strcmp(a, b) == 0; 16 | } 17 | 18 | static inline const char * 19 | thrd_err_as_string(int thrd_err) 20 | { 21 | switch (thrd_err) { 22 | case thrd_success: return "success"; 23 | case thrd_busy: return "busy"; 24 | case thrd_nomem: return "no memory"; 25 | case thrd_timedout: return "timedout"; 26 | 27 | case thrd_error: 28 | default: return "unknown error"; 29 | } 30 | 31 | return "unknown error"; 32 | } 33 | 34 | static inline uint64_t 35 | sdbm_hash(const char *s) 36 | { 37 | uint64_t hash = 0; 38 | 39 | for (; *s != '\0'; s++) { 40 | int c = *s; 41 | hash = c + (hash << 6) + (hash << 16) - hash; 42 | } 43 | 44 | return hash; 45 | } 46 | 47 | enum { 48 | HEX_DIGIT_INVALID = 16 49 | }; 50 | 51 | static inline uint8_t 52 | hex2nibble(char c) 53 | { 54 | switch (c) { 55 | case '0': case '1': case '2': case '3': case '4': 56 | case '5': case '6': case '7': case '8': case '9': 57 | return c - '0'; 58 | 59 | case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 60 | return c - 'a' + 10; 61 | 62 | case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 63 | return c - 'A' + 10; 64 | } 65 | 66 | return HEX_DIGIT_INVALID; 67 | } 68 | -------------------------------------------------------------------------------- /utils/meson.build: -------------------------------------------------------------------------------- 1 | executable('xtgettcap', 'xtgettcap.c') 2 | -------------------------------------------------------------------------------- /vt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "terminal.h" 8 | 9 | void vt_from_slave(struct terminal *term, const uint8_t *data, size_t len); 10 | 11 | static inline int 12 | vt_param_get(const struct terminal *term, size_t idx, int default_value) 13 | { 14 | /* 15 | * We zero excess bits in parsed param values. In most cases this will 16 | * effectively be a no-op; but it prevents negative returns for edge 17 | * cases involving unusually large values. 18 | */ 19 | static_assert(INT_MAX >= 0x7fffffff, "POSIX requires INT_MAX >= 0x7fffffff"); 20 | const unsigned value_mask = 0x7fffffff; 21 | 22 | if (term->vt.params.idx > idx) { 23 | unsigned value = term->vt.params.v[idx].value & value_mask; 24 | return value != 0 ? (int)value : default_value; 25 | } 26 | 27 | return default_value; 28 | } 29 | -------------------------------------------------------------------------------- /xmalloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "xmalloc.h" 5 | #include "debug.h" 6 | 7 | static void * 8 | check_alloc(void *alloc) 9 | { 10 | if (unlikely(alloc == NULL)) { 11 | FATAL_ERROR(__func__, ENOMEM); 12 | } 13 | return alloc; 14 | } 15 | 16 | void * 17 | xmalloc(size_t size) 18 | { 19 | if (unlikely(size == 0)) { 20 | size = 1; 21 | } 22 | return check_alloc(malloc(size)); 23 | } 24 | 25 | void * 26 | xcalloc(size_t nmemb, size_t size) 27 | { 28 | xassert(size != 0); 29 | return check_alloc(calloc(likely(nmemb) ? nmemb : 1, size)); 30 | } 31 | 32 | void * 33 | xrealloc(void *ptr, size_t size) 34 | { 35 | void *alloc = realloc(ptr, size); 36 | return unlikely(size == 0) ? alloc : check_alloc(alloc); 37 | } 38 | 39 | char * 40 | xstrdup(const char *str) 41 | { 42 | return check_alloc(strdup(str)); 43 | } 44 | 45 | char * 46 | xstrndup(const char *str, size_t n) 47 | { 48 | return check_alloc(strndup(str, n)); 49 | } 50 | 51 | char32_t * 52 | xc32dup(const char32_t *str) 53 | { 54 | return check_alloc(c32dup(str)); 55 | } 56 | 57 | static VPRINTF(2) int 58 | xvasprintf_(char **strp, const char *format, va_list ap) 59 | { 60 | va_list ap2; 61 | va_copy(ap2, ap); 62 | int n = vsnprintf(NULL, 0, format, ap2); 63 | if (unlikely(n < 0)) { 64 | FATAL_ERROR("vsnprintf", EILSEQ); 65 | } 66 | va_end(ap2); 67 | *strp = xmalloc(n + 1); 68 | return vsnprintf(*strp, n + 1, format, ap); 69 | } 70 | 71 | char * 72 | xvasprintf(const char *format, va_list ap) 73 | { 74 | char *str; 75 | xvasprintf_(&str, format, ap); 76 | return str; 77 | } 78 | 79 | char * 80 | xasprintf(const char *format, ...) 81 | { 82 | va_list ap; 83 | va_start(ap, format); 84 | char *str = xvasprintf(format, ap); 85 | va_end(ap); 86 | return str; 87 | } 88 | -------------------------------------------------------------------------------- /xmalloc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "char32.h" 10 | #include "macros.h" 11 | 12 | void *xmalloc(size_t size) XMALLOC; 13 | void *xcalloc(size_t nmemb, size_t size) XMALLOC; 14 | void *xrealloc(void *ptr, size_t size); 15 | char *xstrdup(const char *str) XSTRDUP; 16 | char *xstrndup(const char *str, size_t n) XSTRDUP; 17 | char *xasprintf(const char *format, ...) PRINTF(1) XMALLOC; 18 | char *xvasprintf(const char *format, va_list va) VPRINTF(1) XMALLOC; 19 | char32_t *xc32dup(const char32_t *str) XSTRDUP; 20 | 21 | static inline void * 22 | xmemdup(const void *ptr, size_t size) 23 | { 24 | return memcpy(xmalloc(size), ptr, size); 25 | } 26 | 27 | static inline char * 28 | xstrjoin(const char *s1, const char *s2) 29 | { 30 | size_t n1 = strlen(s1); 31 | size_t n2 = strlen(s2); 32 | char *joined = xmalloc(n1 + n2 + 1); 33 | memcpy(joined, s1, n1); 34 | memcpy(joined + n1, s2, n2 + 1); 35 | return joined; 36 | } 37 | 38 | static inline char * 39 | xstrjoin3(const char *s1, const char *s2, const char *s3) 40 | { 41 | size_t n1 = strlen(s1); 42 | size_t n2 = strlen(s2); 43 | size_t n3 = strlen(s3); 44 | char *joined = xmalloc(n1 + n2 + n3 + 1); 45 | memcpy(joined, s1, n1); 46 | memcpy(joined + n1, s2, n2); 47 | memcpy(joined + n1 + n2, s3, n3 + 1); 48 | return joined; 49 | } 50 | -------------------------------------------------------------------------------- /xsnprintf.c: -------------------------------------------------------------------------------- 1 | #include "xsnprintf.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include "debug.h" 7 | #include "macros.h" 8 | 9 | /* 10 | * ISO C doesn't require vsnprintf(3) to set errno on failure, but 11 | * POSIX does: 12 | * 13 | * "If an output error was encountered, these functions shall return 14 | * a negative value and set errno to indicate the error." 15 | * 16 | * The mandated errors of interest are: 17 | * 18 | * - EILSEQ: A wide-character code does not correspond to a valid character 19 | * - EOVERFLOW: The value of n is greater than INT_MAX 20 | * - EOVERFLOW: The value to be returned is greater than INT_MAX 21 | * 22 | * ISO C11 states: 23 | * 24 | * "The vsnprintf function returns the number of characters that would 25 | * have been written had n been sufficiently large, not counting the 26 | * terminating null character, or a negative value if an encoding error 27 | * occurred. Thus, the null-terminated output has been completely 28 | * written if and only if the returned value is nonnegative and less 29 | * than n." 30 | * 31 | * See also: 32 | * 33 | * - ISO C11 §7.21.6.12p3 34 | * - https://pubs.opengroup.org/onlinepubs/9699919799/functions/vsnprintf.html 35 | * - https://pubs.opengroup.org/onlinepubs/9699919799/functions/snprintf.html 36 | */ 37 | static size_t 38 | xvsnprintf(char *restrict buf, size_t n, const char *restrict format, va_list ap) 39 | { 40 | int len = vsnprintf(buf, n, format, ap); 41 | if (unlikely(len < 0 || len >= (int)n)) { 42 | FATAL_ERROR(__func__, (len < 0) ? errno : ENOBUFS); 43 | } 44 | return (size_t)len; 45 | } 46 | 47 | size_t 48 | xsnprintf(char *restrict buf, size_t n, const char *restrict format, ...) 49 | { 50 | va_list ap; 51 | va_start(ap, format); 52 | size_t len = xvsnprintf(buf, n, format, ap); 53 | va_end(ap); 54 | return len; 55 | } 56 | -------------------------------------------------------------------------------- /xsnprintf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "macros.h" 6 | 7 | size_t xsnprintf(char *restrict buf, size_t n, const char *restrict format, ...) PRINTF(3) NONNULL_ARGS; 8 | --------------------------------------------------------------------------------