├── .gitignore ├── README.md ├── assets ├── getfonts.rc ├── getgo.rc ├── getjava.rc ├── getopam.sh ├── getpandoc.sh ├── getrust.sh └── getscala.rc ├── bin ├── Accls ├── Agodef ├── Agodoc ├── Agofmt ├── Agoimp ├── Agopls ├── Agorun ├── Amd ├── Ametals ├── Aocaml ├── Apython ├── Aqw ├── Ascalafmt ├── Cmd ├── F ├── F+ ├── F- ├── Fdeja ├── Lassist ├── Lcomp ├── Ldef ├── Lfmt ├── Lhov ├── Lrefs ├── Lrn ├── Lsig ├── Lsyms ├── Ltype ├── Lws ├── Lws+ ├── Lws- ├── Perl ├── Python ├── Run ├── Watch ├── acal ├── acme ├── cam ├── emoji ├── helloml ├── ipso ├── readmail ├── riostart └── screenshot ├── desktop ├── 9term.desktop ├── Xresources ├── acme.desktop ├── alacritty.yml ├── cwmrc ├── dialogrc ├── display_handler ├── foot.init ├── gitconfig ├── plan9.sh ├── rio.rasi ├── starship.toml ├── swaywm_config ├── vimrc ├── wezterm.lua ├── xbindkeysrc └── xmodmap ├── doc └── p9p-email.md ├── lib ├── plumbing └── profile ├── mail ├── acal.py ├── acal.rc └── pipefrom └── screenshots └── simple.png /.gitignore: -------------------------------------------------------------------------------- 1 | src/* 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # plan9port linux environment 2 | 3 | Configurations, clients, scripts and guides to work with plan9ports 4 | in linux. 5 | 6 | Because I always forgot to set up something, I just wanna clone this 7 | and be ready. 8 | 9 | I just understood why `/usr/local/plan9` is a good compromise. You just 10 | need to run plan9port on OSX, Linux and FreeBSD, and the easiest way to 11 | set up a profile which behaves as expected on the three systems is by 12 | using a hardcoded system path. 13 | 14 | The `NAMESPACE` variable is something ugly too. I decided to create a 15 | `$HOME/.ns/N` direcotry as a namespace point. There is a funcion in 16 | the profile called `nssetup N` which creates folder in case it does not 17 | exists, and return the path created to set up the NAMESPACE variable. 18 | 19 | # Install 20 | 21 | If you want to contribute to plan9port, it is convenient to clone the 22 | repository on your $HOME folder and then link that to `/usr/local/plan9` 23 | so everything works. 24 | 25 | ```` 26 | % git clone https://github.com/9fans/plan9port.git $HOME/.local/plan9 27 | % sudo ln -s $HOME/.local/plan9 /usr/local/plan9 28 | ```` 29 | 30 | I use `~/.local/plan9` instead of something like `~/src` to remind myself 31 | I cannot left the tree broken, because I use it. But still I want to test 32 | things and make some changes. 33 | 34 | 35 | # Assets 36 | 37 | ## Fonts 38 | 39 | The `getfonts.rc` script downloads fonts and install them on your `$HOME`. 40 | These days I use IBM Plex family. 41 | 42 | One caveat with `fontsrv` is that it does not support fallback fonts on 43 | Linux. It seems to work on OSX. If you need emoji support, 44 | you can use DejaVuSans which has a good UTF support including some emojis. 45 | 46 | I have set up that font as default in the profile. 47 | 48 | There are Three scripts to play with fonts inside acme: 49 | 50 | - `F+` → Increases the size of the current font, by 1 point or the number 51 | passed as argument 52 | 53 | - `F-` → Decreases the size of the cuurrent font, by 1 point or the 54 | number passed as argument 55 | 56 | - `F` → Sets the current font to be the one passed by argument. If the 57 | font is not found, it greps through the font list searching for the 58 | pattern passed by argument 59 | 60 | ## Programming languages 61 | 62 | I need to use a couple programming languages daily, so I build a couple of scripts to set up the environment for them. 63 | I prefer to manage these environments and versions carefully instead of installing system-wide environments. 64 | 65 | The profile loads a lot of variables for each language. 66 | 67 | - `getgo.rc`--> installs golang in $HOME/.local/go 68 | - `getjava.rc` --> install java in $HOME/.local/java 69 | - `getscala.rc` --> install metals and scalafmt into $HOME/.local/bin 70 | - `opam.rc` --> install opam into $HOME/local/bin (beware this is a curl | bash) 71 | 72 | # Acme 73 | 74 | I use [acme-lsp](https://github.com/fhs/acme-lsp) to work with those 75 | programming languages sometimes. 76 | 77 | - `gopls` --> golang language server 78 | - `jdt` --> java language server (from eclipse) 79 | - `metals` --> scala language server 80 | - `ocaml-lsp` --> ocaml language server 81 | - `ccls` --> C language server 82 | 83 | And also [xplor](https://github.com/mpl/xplor) to naviage code in some 84 | projects with deep nested directories. 85 | 86 | # Factotum 87 | 88 | I use factotum as a cheap password manager sometimes. For that I have 89 | created [src/pass.c](src/pass.c). It is probably insecure, but a better 90 | option that a plain text file laying araound or a complex password 91 | manager. 92 | 93 | 94 | # Email 95 | 96 | I use nedmail and upas to read email. I have put some documentation in 97 | [docs/p9p-email.md](docs/p9p-email.md) 98 | 99 | There are some scripts I use in [mail/](mail/) for reading and sending 100 | email using plan9ports programs. 101 | 102 | # Dekstop interface 103 | 104 | Still trying to find something satisfactory. Just use whatever it is at 105 | hand for now. 106 | 107 | There are too many things out there. Playing nice will them is too 108 | painfull. So I have removed all custom configurations and helpers to 109 | deal with graphical environment 110 | 111 | I will let a way to launch 9term and acme with the plan9port profile 112 | loaded, like .dekstop files or BSDs and Linux. 113 | 114 | -------------------------------------------------------------------------------- /assets/getfonts.rc: -------------------------------------------------------------------------------- 1 | #!/usr/local/plan9/bin/rc 2 | 3 | DEST='' 4 | os=`{uname} 5 | switch($os) { 6 | case 'Darwin' 7 | DEST=$home/Library/Fonts 8 | case 'Linux' 9 | DEST=$home/.local/share/fonts 10 | } 11 | 12 | 13 | # https://github.com/githubnext/monaspace/releases/tag/v1.000 14 | fn monaspace { 15 | fonts=('https://github.com/githubnext/monaspace/releases/download/v1.000/monaspace-v1.000.zip') 16 | install 'monaspace' $fonts 17 | } 18 | 19 | # Free Font derived form Lucida to be included with Go programming language 20 | # https://blog.golang.org/go-fonts 21 | fn gofont { 22 | git clone https://go.googlesource.com/image 23 | mkdir -p $DEST/gofont 24 | cp image/font/gofont/ttfs/* $DEST/gofont 25 | } 26 | 27 | fn iosevka { 28 | fonts=('https://github.com/be5invis/Iosevka/releases/download/v26.3.3/ttf-iosevka-26.3.3.zip' 'https://github.com/be5invis/Iosevka/releases/download/v26.3.3/ttf-iosevka-term-26.3.3.zip' 'https://github.com/be5invis/Iosevka/releases/download/v26.3.3/ttf-iosevka-slab-26.3.3.zip' 'https://github.com/be5invis/Iosevka/releases/download/v26.3.3/ttf-iosevka-etoile-26.3.3.zip' 'https://github.com/be5invis/Iosevka/releases/download/v26.3.3/ttf-iosevka-fixed-26.3.3.zip' 'https://github.com/be5invis/Iosevka/releases/download/v26.3.3/ttf-iosevka-aile-26.3.3.zip' ) 29 | install 'iosevka' $fonts 30 | } 31 | 32 | fn huerta { 33 | fonts=('https://www.huertatipografica.com/free_download/132' 'https://www.huertatipografica.com/free_download/23' 'https://www.huertatipografica.com/free_download/164' 'https://www.huertatipografica.com/free_download/144' 'https://www.huertatipografica.com/free_download/45' 'https://www.huertatipografica.com/free_download/142') 34 | install 'huerta' $fonts 35 | } 36 | 37 | fn nerdfonts { 38 | fonts=('https://github.com/ryanoasis/nerd-fonts/releases/download/v2.1.0/Go-Mono.zip' 'https://github.com/ryanoasis/nerd-fonts/releases/download/v2.1.0/3270.zip' 'https://github.com/ryanoasis/nerd-fonts/releases/download/v2.1.0/BigBlueTerminal.zip' 'https://github.com/ryanoasis/nerd-fonts/releases/download/v2.1.0/FiraMono.zip' 'https://github.com/ryanoasis/nerd-fonts/releases/download/v2.1.0/Monoid.zip' 'https://github.com/ryanoasis/nerd-fonts/releases/download/v2.1.0/SourceCodePro.zip' 'https://github.com/ryanoasis/nerd-fonts/releases/download/v2.1.0/Terminus.zip') 39 | install 'nerdfonts' $fonts 40 | } 41 | 42 | fn juliamono { 43 | fonts=('https://github.com/cormullion/juliamono/releases/download/v0.038/JuliaMono.zip') 44 | install 'juliamono' $fonts 45 | } 46 | 47 | fn nimbus { 48 | fonts=('https://github.com/ArtifexSoftware/urw-base35-fonts/archive/refs/tags/20200910.zip') 49 | install 'nimbus' $fonts 50 | } 51 | 52 | fn minion { 53 | fonts=('https://www.wfonts.com/download/data/2016/05/26/minion-pro/minion-pro.zip') 54 | install 'minion' $fonts 55 | } 56 | 57 | fn atkinson { 58 | fonts=('https://www.brailleinstitute.org/wp-content/uploads/atkinson-hyperlegible-font/Atkinson-Hyperlegible-Font-Print-and-Web-2020-0514.zip') 59 | install 'atkinson' $fonts 60 | } 61 | 62 | # Opensource font sponsored by Red Hat 63 | # http://overpassfont.org/ 64 | fn overpass { 65 | fonts=('https://github.com/RedHatBrand/Overpass/releases/download/3.0.2/overpass-desktop-fonts.zip') 66 | install 'overpass' $fonts 67 | } 68 | 69 | # Opensource font sponsored by Adobe 70 | # https://github.com/adobe-fonts/ 71 | fn adobe { 72 | fonts=('https://github.com/adobe-fonts/source-serif-pro/releases/download/3.001R/source-serif-pro-3.001R.zip' 'https://github.com/adobe-fonts/source-sans-pro/releases/download/3.006R/source-sans-pro-3.006R.zip' 'https://github.com/adobe-fonts/source-code-pro/releases/download/2.030R-ro%2F1.050R-it/source-code-pro-2.030R-ro-1.050R-it.zip') 73 | install 'adobe' $fonts 74 | } 75 | 76 | # Opensource font Copper Hewwit by Chester Jenkins 77 | # https://www.cooperhewitt.org/open-source-at-cooper-hewitt/cooper-hewitt-the-typeface-by-chester-jenkins/ 78 | fn cooper { 79 | fonts=('https://uh8yh30l48rpize52xh0q1o6i-wpengine.netdna-ssl.com/wp-content/uploads/fonts/CooperHewitt-OTF-public.zip') 80 | install 'cooper' $fonts 81 | } 82 | 83 | # Opensource font by David Johnatan Ross 84 | # https://input.fontbureau.com/ 85 | fn input { 86 | fonts=('https://input.djr.com/build/?fontSelection=whole&a=0&g=0&i=0&l=0&zero=0&asterisk=0&braces=0&preset=default&line-height=1.2&accept=I+do&email=') 87 | install 'input' $fonts 88 | } 89 | 90 | # Opensource font by 91 | # https://practicaltypography.com/fonts/charter.zip 92 | fn charter { 93 | fonts=('https://practicaltypography.com/fonts/Charter%20210112.zip') 94 | install 'charter' $fonts 95 | } 96 | 97 | # Open fonts by SIL 98 | # https://software.sil.org/fonts/ 99 | 100 | # Opensource font by 101 | # http://terminus-font.sourceforge.net/ 102 | fn terminus { 103 | fonts=('https://files.ax86.net/terminus-ttf/files/latest.zip') 104 | install 'terminus' $fonts 105 | } 106 | 107 | # Open fonts by D. Knuth ported to TTF 108 | # http://mirrors.ctab,org/fonts 109 | fn computermodern { 110 | fonts=('http://mirrors.ctan.org/fonts/cm-unicode.zip') 111 | install 'computer_modern' $fonts 112 | } 113 | 114 | # Open source fonts by IBM 115 | # https://github.com/IBM/plex 116 | fn ibm { 117 | fonts=('https://github.com/IBM/plex/releases/download/v4.0.2/OpenType.zip' ) 118 | install 'ibmplex' $fonts 119 | } 120 | 121 | # Free font by Huerta Tipografica 122 | # https://www.huertatipografica.com 123 | fn bitter { 124 | fonts=('https://www.huertatipografica.com/free_download/144') 125 | install 'bitter' $fonts 126 | } 127 | 128 | # Opensource font by Mozilla 129 | # https://github.com/mozilla/fira 130 | fn fira { 131 | fonts=('https://github.com/mozilla/Fira/archive/4.202.zip') 132 | install 'fira' $fonts 133 | } 134 | 135 | # Open source fonts from Google 136 | fn noto { 137 | fonts=('https://noto-website-2.storage.googleapis.com/pkgs/Noto-hinted.zip') 138 | install 'noto' $fonts 139 | } 140 | 141 | fn lora { 142 | fonts=('https://www.fontsquirrel.com/fonts/download/lora') 143 | install 'lora' $fonts 144 | } 145 | 146 | fn orbitron { 147 | fonts=('https://github.com/theleagueof/orbitron/archive/master.zip') 148 | install 'orbitron' $fonts 149 | } 150 | 151 | fn montserrat { 152 | fonts=('https://github.com/JulietaUla/Montserrat/archive/v7.200.zip') 153 | install 'monserrat' $fonts 154 | } 155 | 156 | # 'https://raw.githubusercontent.com/Zygo/xscreensaver/master/OSX/gallant12x22.ttf' 157 | fn sun { 158 | curl -L 'https://raw.githubusercontent.com/Zygo/xscreensaver/master/OSX/gallant12x22.ttf' > $DEST/gallant12x22.ttf 159 | } 160 | 161 | fn dec { 162 | fonts=('https://dl.dafont.com/dl/?f=dec_terminal_modern') 163 | install 'dec' $fonts 164 | } 165 | 166 | fn ibm3270 { 167 | fonts=('https://github.com/rbanffy/3270font/releases/download/v2.0.4/3270_fonts_ece94f6.zip' ) 168 | install '3270' $fonts 169 | } 170 | 171 | fn ibarra { 172 | fonts=('https://github.com/googlefonts/ibarrareal/archive/master.zip') 173 | install 'ibarra' $fonts 174 | } 175 | 176 | fn copy { 177 | name=$1 178 | shift 179 | mkdir -p $DEST/$name 180 | 181 | cp *.otf $DEST/$name || cp *.ttf $DEST/$name 182 | } 183 | 184 | fn install { 185 | name=$1 186 | shift 187 | fonts=$* 188 | 189 | for(i in `{9 seq 1 1 $#fonts}) { 190 | echo Downloading $fonts($i) into $i.zip 191 | curl -L -o $i.zip $fonts($i) 192 | echo Uncompressing $i.zip 193 | /usr/bin/unzip -j $i.zip 194 | echo Copying into $name 195 | copy $name 196 | echo Remove $i.zip 197 | rm $i.zip 198 | } 199 | } 200 | 201 | ALL=(monaspace gofont iosevka huerta nerdfonts juliamono nimbus minion atkinson ibarra overpass adobe cooper input charter terminus computermodern ibm bitter fira gofont noto lora orbitron montserrat sun dec ibm3270) 202 | 203 | if(test $#* -eq 0 ) { 204 | echo Select all or one of the following fonts: 205 | echo $ALL 206 | exit 207 | } 208 | 209 | FONTS=$* 210 | if(test -z $FONTS) { 211 | echo 'Select all or one of the following fonts:' 212 | echo $ALL 213 | exit 214 | } 215 | 216 | for(font in $FONTS) { 217 | tmp=`{mktemp -d} 218 | cd $tmp 219 | echo Installing $font 220 | $font 221 | cd 222 | echo Remove $tmp 223 | } 224 | 225 | -------------------------------------------------------------------------------- /assets/getgo.rc: -------------------------------------------------------------------------------- 1 | #!/usr/local/plan9/bin/rc 2 | 3 | os=`{uname | 9 tr [A-Z] [a-z]} 4 | 5 | GOVERSION=1.21.3 6 | DEST=$home/.local/go/ 7 | GOROOT=$DEST'/'$GOVERSION 8 | URL=https://go.dev/dl/go$GOVERSION.$os-amd64.tar.gz 9 | 10 | switch($os) { 11 | case 'darwin' 12 | URL=https://go.dev/dl/go$GOVERSION.darwin-arm64.tar.gz 13 | } 14 | 15 | if(test ! -d $GOROOT) { 16 | echo Installing Go $GOVERSION 17 | mkdir -p $DEST 18 | cd $DEST 19 | curl -L $URL | 9 gunzip | 9 tar x 20 | mv go $GOVERSION 21 | exit 22 | } 23 | 24 | path=($GOROOT/bin $path) 25 | 26 | # 3rd party 27 | go install 9fans.net/go/acme/editinacme@latest 28 | go install 9fans.net/go/acme/Watch@latest 29 | go install 9fans.net/go/acme/Dict@latest 30 | go install github.com/mpl/xplor@latest 31 | go install github.com/rogpeppe/agitlink@latest 32 | 33 | # other tools 34 | go install rsc.io/mailgun/cmd/mailgun-mail@latest 35 | go install rsc.io/mailgun/cmd/mailgun-sendmail@latest 36 | 37 | # lang server 38 | go install golang.org/x/tools/gopls@latest 39 | go install 9fans.net/acme-lsp/cmd/acme-lsp@latest 40 | go install 9fans.net/acme-lsp/cmd/L@latest 41 | 42 | # get ivy 43 | go install robpike.io/ivy@latest 44 | 45 | -------------------------------------------------------------------------------- /assets/getjava.rc: -------------------------------------------------------------------------------- 1 | #!/usr/local/plan9/bin/rc 2 | 3 | os=`{uname | 9 tr [A-Z] [a-z]} 4 | switch($os) { 5 | case linux 6 | JAVA_URL=https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.11%2B9/OpenJDK11U-jdk_x64_linux_hotspot_11.0.11_9.tar.gz 7 | case darwin 8 | JAVA_URL=https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.11%2B9/OpenJDK11U-jdk_x64_mac_hotspot_11.0.11_9.tar.gz 9 | case * 10 | echo $OS not supported 11 | exit 12 | } 13 | 14 | JAVA_VERSION=11.0.11 15 | 16 | JAVA_HOME=$HOME'/.local/java/jdk/'$JAVA_VERSION 17 | 18 | mkdir -p $JAVA_HOME 19 | curl -L $JAVA_URL | gunzip | @{cd $JAVA_HOME && tar xRT && mv jdk-11.0.11+9/* . && rmdir jdk-11.0.11+9} 20 | 21 | PATH=$JAVA_HOME/bin:$PATH 22 | 23 | # Install maven 24 | MVN_VERSION=3.8.1 25 | MVN_URL=http://apache.uvigo.es/maven/maven-3/3.8.1/binaries/apache-maven-3.8.1-bin.tar.gz 26 | MVN_HOME=$HOME/.local/java/mvn/$MVN_VERSION 27 | mkdir -p $MVN_HOME 28 | curl -L $MVN_URL | gunzip | @{cd $MVN_HOME && tar xRT && mv apache-maven-3.8.1/* . && rmdir apache-maven-3.8.1} 29 | 30 | PATH=$PATH:$MVN_HOME 31 | 32 | # install eclipse jdt lanague server 33 | JDT_VERSION=1.1.2 34 | JDT_URL=http://download.eclipse.org/jdtls/milestones/1.1.2/jdt-language-server-1.1.2-202105191944.tar.gz 35 | JDT_HOME=$HOME/.local/java/jdt/$JDT_VERSION 36 | mkdir -p $JDT_HOME 37 | curl -L $JDT_URL | gunzip | @{cd $JDT_HOME && tar xRT} 38 | 39 | -------------------------------------------------------------------------------- /assets/getopam.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | sh <(curl -sL https://raw.githubusercontent.com/ocaml/opam/master/shell/install.sh) 4 | 5 | -------------------------------------------------------------------------------- /assets/getpandoc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh 4 | 5 | dir=$(mktemp -d) 6 | curl -L "https://github.com/jgm/pandoc/releases/download/2.11.3.2/pandoc-2.11.3.2-linux-amd64.tar.gz" | tar zx --strip-components 1 -C "$dir" 7 | mv $dir/bin/pandoc $HOME/.local/bin/ 8 | 9 | # pandoc templates 10 | curl 'https://raw.githubusercontent.com/ryangrose/easy-pandoc-templates/master/copy_templates.sh' | bash 11 | 12 | 13 | -------------------------------------------------------------------------------- /assets/getrust.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cargo install hacksaw 4 | cargo install shotgun 5 | cargo install alacritty 6 | -------------------------------------------------------------------------------- /assets/getscala.rc: -------------------------------------------------------------------------------- 1 | #!/usr/local/plan9/bin/rc 2 | 3 | os=`{uname | 9 tr [A-Z] [a-z]} 4 | 5 | JAVA_VERSION=11.0.11 6 | 7 | JAVA_HOME=$HOME'/.local/java/jdk/'$JAVA_VERSION 8 | 9 | # Install SBT 10 | SBT_VERSION=1.5.3 11 | SBT_URL='https://github.com/sbt/sbt/releases/download/v'$SBT_VERSION'/sbt-'$SBT_VERSION'.tgz' 12 | SBT_HOME=$HOME'/.local/java/sbt/'$SBT_VERSION 13 | mkdir -p $SBT_HOME 14 | curl -L $SBT_URL | gunzip | @{cd $SBT_HOME && tar xRT && mv sbt/* . && rmdir sbt} 15 | 16 | path=( $path $SBT_HOME/bin) 17 | MVN=$MVN_HOME/bin/mvn 18 | SBT=$SBT_HOME/bin/sbt 19 | 20 | # Install Courier 21 | COURSIER_VERSION=current 22 | COURSIER_URL=https://git.io/coursier-cli 23 | curl -Lo $home'/.local/bin/coursier' $COURSIER_URL 24 | chmod +x $home'/.local/bin/coursier' 25 | 26 | path=($path $JAVA_HOME/bin $HOME/.local/bin $MVN_HOME/bin $SBT_HOME/bin) 27 | 28 | # Install metals 29 | 30 | $home/.local/bin/coursier bootstrap \ 31 | --java-opt -XX:+UseG1GC \ 32 | --java-opt -XX:+UseStringDeduplication \ 33 | --java-opt -Xss4m \ 34 | --java-opt -Xms100m \ 35 | --java-opt -Dmetals.verbose=on \ 36 | --java-opt -Dmetals.http=on \ 37 | --java-opt -Dmetals.java-home=$JAVA_HOME \ 38 | --java-opt -Dmetals.maven-script=$MVN \ 39 | --java-opt -Dmetals.sbt-script=$SBT \ 40 | org.scalameta:metals_2.12:0.10.4 -o $home'/.local/bin/metals' -f 41 | 42 | 43 | # Install scalafmt 44 | VERSION=3.0.0 45 | curl --fail -Lo $home'/.local/bin/scalafmt' https://github.com/scalameta/scalafmt/releases/download/v3.0.0-RC4/scalafmt-linux-glibc 46 | -------------------------------------------------------------------------------- /bin/Accls: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | rootDir=$(pwd) 3 | workspaces=$rootDir 4 | 5 | if [ ! -z "$1" ]; then 6 | workspaces="$rootDir:$1" 7 | fi 8 | 9 | exec 1> /tmp/$(mktemp acme-lsp.log.XXX) 10 | exec 2>&1 11 | 12 | acme-lsp --rootdir $rootDir -v -server "(\.c)|(\.ccp)$:ccls" -workspaces "$workspaces" 13 | -------------------------------------------------------------------------------- /bin/Agodef: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | echo 3 | godef -acme -a | tail -n+2 | grep -v -e '^[[:space:]]*$' 4 | -------------------------------------------------------------------------------- /bin/Agodoc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | 3 | . 9.rc 4 | . $PLAN9/lib/acme.rc 5 | 6 | fn event { 7 | # $1 - c1 origin of event 8 | # $2 - c2 type of action 9 | # $3 - q0 beginning of selection 10 | # $4 - q1 end of selection 11 | # $5 - eq0 beginning of expanded selection 12 | # $6 - eq1 end of expanded selection 13 | # $7 - flag 14 | # $8 - nr number of runes in $9 15 | # $9 - text 16 | # $10 - chorded argument 17 | # $11 - origin of chorded argument 18 | 19 | switch($1$2){ 20 | case E* # write to body or tag 21 | case F* # generated by ourselves; ignore 22 | case K* # type away we do not care 23 | case Mi # mouse: text inserted in tag 24 | case MI # mouse: text inserted in body 25 | case Md # mouse: text deleted from tag 26 | case MD # mouse: text deleted from body 27 | case Ml # mouse: button 3 in tag 28 | winwriteevent $* 29 | case Mx MX # button 2 in tag or body 30 | winwriteevent $* 31 | 32 | case ML # button 3 in body 33 | { 34 | tag=`{winread tag | awk '{print $1}' } 35 | last=`{winread tag | awk '{print $1}' | sed 's/\// /g' | awk '{print $NR}'} 36 | godocwin $tag.$9/ $last.$9 37 | } & 38 | } 39 | } 40 | 41 | fn godocwin { 42 | newwindow 43 | 44 | winname $1 45 | echo -n ':0' | winwrite tag 46 | q=`{echo $2 | sed 's/\./ /g'} 47 | 48 | switch($#*){ 49 | case 1 50 | echo ' 51 | Agodoc Usage: 52 | Pass as package.Function to Agodoc (Chord 2-1) to see its documentation 53 | ' | winwrite body 54 | case 2 55 | godoc $q >[2=1] | winwrite body 56 | } 57 | winctl clean 58 | wineventloop 59 | } 60 | 61 | switch($#*){ 62 | case 0 63 | godocwin /agodoc/godoc 64 | 65 | case * 66 | for(i) { 67 | godocwin /agodoc/$i $i 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /bin/Agofmt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | ##### !/usr/bin/env 9 rc 3 | fn aread { 9p read acme/$winid/$1 } 4 | fn awrite { 9p write acme/$winid/$1 } 5 | 6 | atag=`{aread tag | awk '{print $1}' | sed 's/\//#/g'} 7 | ftmp=`{mktemp /tmp/Agofmt.XXXXXX} 8 | etmp=`{mktemp /tmp/Agofmt.XXXXXX} 9 | if (aread body | gofmt $* >$ftmp >[2]$etmp) { 10 | # Don't dirty the window if you don't have to 11 | if (! aread body | cmp /dev/stdin $ftmp >/dev/null >[2=1] ) { 12 | echo -n mark | awrite ctl 13 | echo -n nomark | awrite ctl 14 | echo -n , | awrite addr 15 | awrite data <$ftmp 16 | echo -n mark | awrite ctl 17 | # put us at the top of the file, rather than the bottom 18 | echo -n '#0' | awrite addr 19 | echo -n 'dot=addr' | awrite ctl 20 | echo -n show | awrite ctl 21 | } 22 | } 23 | if not { 24 | sed 's|^|'^$%^'|' $etmp >[1=2] 25 | } 26 | rm -f $ftmp $etmp 27 | 28 | -------------------------------------------------------------------------------- /bin/Agoimp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | 3 | fn aread { 4 | 9p read acme/$winid/$1 5 | } 6 | 7 | fn awrite { 8 | 9p write acme/$winid/$1 9 | } 10 | 11 | ftmp=`{mktemp /tmp/Agofmt.XXXXXX} 12 | etmp=`{mktemp /tmp/Agofmt.XXXXXX} 13 | 14 | if (aread body | goimports $*>$ftmp >[2]$etmp) { 15 | # Don't dirty the window if you don't have to 16 | if (! aread body | cmp /dev/stdin $ftmp >/dev/null >[2=1]) { 17 | echo -n mark | awrite ctl 18 | echo -n nomark | awrite ctl 19 | echo -n , | awrite addr 20 | awrite data <$ftmp 21 | echo -n mark | awrite ctl 22 | # put us at the top of the file, rather than the bottom 23 | echo -n '#0' | awrite addr 24 | echo -n 'dot=addr' | awrite ctl 25 | echo -n show | awrite ctl 26 | } 27 | } 28 | if not { 29 | sed 's|^|'^$%^'|' $etmp >[1=2] 30 | } 31 | 32 | rm -f $ftmp $etmp 33 | 34 | -------------------------------------------------------------------------------- /bin/Agopls: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | acme-lsp -server '([/\\]go\.mod)|([/\\]go\.sum)|(\.go)$:gopls serve' -workspaces $@ 3 | -------------------------------------------------------------------------------- /bin/Agorun: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | ######!/usr/bin/env 9 rc 3 | 4 | . 9.rc 5 | dir=acme/acme/$winid 6 | 7 | fn rd { 8 | 9p read $dir/$1 || { echo 9p failed >[1=2]; exit 9p } 9 | } 10 | 11 | tag=`{rd tag} 12 | if(~ $tag(1) */){ 13 | cd $tag(1) 14 | go build -o go.out && ./go.out && rm go.out 15 | } 16 | if not { 17 | if(~ $tag(1) *.go){ 18 | file=`{basename $tag(1)} 19 | dir1=`{dirname $tag(1)} 20 | cd $dir1 21 | go run $file 22 | } 23 | if not { 24 | echo window $tag(1) is not a directory or Go source file >[1=2] 25 | exit 'not a directory or Go source file' 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /bin/Amd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | 3 | . 9.rc 4 | . $PLAN9/lib/acme.rc 5 | 6 | # this needs a plumbing rule for URLS like: 7 | # 8 | # type is text 9 | # data matches '(https?|ftp|file|news|nntp|telnet|wais|prospero)://.*' 10 | # plumb to web 11 | # plumb start firefox $0 12 | 13 | rm /tmp/Amd*.html >[2]/dev/null 14 | file=`{winread tag | awk -F ' Del Snarf ' '{print $1}' | sed 1q} 15 | tmpfile=`{mktemp /tmp/Amd.XXXXXX.html} 16 | cat $"file | pandoc -f gfm -t html --self-contained -o $tmpfile >[2]/dev/null 17 | plumb file://$tmpfile 18 | -------------------------------------------------------------------------------- /bin/Ametals: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | rootDir=$(pwd) 3 | workspaces=$rootDir 4 | 5 | if [ ! -z "$1" ]; then 6 | workspaces="$rootDir:$1" 7 | fi 8 | 9 | exec 1> /tmp/$(mktemp acme-lsp.log.XXX) 10 | exec 2>&1 11 | 12 | acme-lsp --rootdir $rootDir -v -server "(\.scala)|(\.sbt)$:metals" -workspaces "$workspaces" 13 | -------------------------------------------------------------------------------- /bin/Aocaml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | rootDir=$(pwd) 3 | workspaces=$rootDir 4 | 5 | source ~/.profile 6 | 7 | eval $(opam env) 8 | 9 | if [ ! -z "$1" ]; then 10 | workspaces="$rootDir:$1" 11 | fi 12 | 13 | exec 1> /tmp/$(mktemp acme-lsp.log.XXX) 14 | exec 2>&1 15 | 16 | acme-lsp --rootdir $rootDir -v -server '\.ml$@ocaml,\.mli$@ocaml,\.rml$@reasonml:ocamllsp' -workspaces "$workspaces" 17 | 18 | -------------------------------------------------------------------------------- /bin/Apython: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | rootDir=$(pwd) 3 | workspaces=$rootDir 4 | 5 | if [ ! -z "$1" ]; then 6 | workspaces="$rootDir:$1" 7 | fi 8 | 9 | acme-lsp --rootdir $rootDir -v -server "(\.py)$:pyls" -workspaces "$workspaces" 10 | -------------------------------------------------------------------------------- /bin/Aqw: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | 3 | . 9.rc 4 | . $PLAN9/lib/acme.rc 5 | 6 | fn event { 7 | # $1 - c1 origin of event 8 | # $2 - c2 type of action 9 | # $3 - q0 beginning of selection 10 | # $4 - q1 end of selection 11 | # $5 - eq0 beginning of expanded selection 12 | # $6 - eq1 end of expanded selection 13 | # $7 - flag 14 | # $8 - nr number of runes in $9 15 | # $9 - text 16 | # $10 - chorded argument 17 | # $11 - origin of chorded argument 18 | 19 | switch($1$2){ 20 | case E* # write to body or tag 21 | case F* # generated by ourselves; ignore 22 | case K* # type away we do not care 23 | case Mi # mouse: text inserted in tag 24 | case MI # mouse: text inserted in body 25 | case Md # mouse: text deleted from tag 26 | case MD # mouse: text deleted from body 27 | 28 | case Mx MX # button 2 in tag or body 29 | winread | sed $3,$4s/*/"&"/g | winwrite 30 | winwriteevent $* 31 | 32 | case Ml ML # button 3 in tag or body 33 | echo button 3 34 | } 35 | } 36 | 37 | wineventloop 38 | 39 | switch($#*){ 40 | case 1 41 | echo -n '"'$1'"' 42 | case * 43 | echo need a string 44 | } 45 | -------------------------------------------------------------------------------- /bin/Ascalafmt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | ##### !/usr/bin/env 9 rc 3 | fn aread { 9p read acme/$winid/$1 } 4 | fn awrite { 9p write acme/$winid/$1 } 5 | 6 | atag=`{aread tag | awk '{print $1}' | sed 's/\//#/g'} 7 | ftmp=`{mktemp /tmp/Ascalafmt.XXXXXX} 8 | etmp=`{mktemp /tmp/Ascalafmt.XXXXXX} 9 | if (aread body | scalafmt --stdin $* >$ftmp >[2]$etmp) { 10 | # Don't dirty the window if you don't have to 11 | if (! aread body | cmp /dev/stdin $ftmp >/dev/null >[2=1] ) { 12 | echo -n mark | awrite ctl 13 | echo -n nomark | awrite ctl 14 | echo -n , | awrite addr 15 | awrite data <$ftmp 16 | echo -n mark | awrite ctl 17 | # put us at the top of the file, rather than the bottom 18 | echo -n '#0' | awrite addr 19 | echo -n 'dot=addr' | awrite ctl 20 | echo -n show | awrite ctl 21 | } 22 | } 23 | if not { 24 | sed 's|^|'^$%^'|' $etmp >[1=2] 25 | } 26 | rm -f $ftmp $etmp 27 | 28 | -------------------------------------------------------------------------------- /bin/Cmd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | user=$1 4 | IFS=";" 5 | inventory=("${2}") 6 | commands=("${3}") 7 | 8 | 9 | IFS=";" 10 | for command in ${commands}; do 11 | for host in ${inventory}; do 12 | ssh -t ${user}@${host} "bash -c \"${command}\"" 13 | done 14 | done 15 | -------------------------------------------------------------------------------- /bin/F: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | 3 | if(test $#* -eq 0) { 4 | exit 5 | } 6 | 7 | . 9.rc 8 | . $PLAN9/lib/acme.rc 9 | 10 | nx=0 11 | if(test $#* -gt 1) { 12 | nx=$2 13 | } 14 | 15 | newfont=(`{9p ls font | 9 grep '^'$1'$'}) 16 | if (test $#newfont -eq 1) { 17 | ctl=(`{9p read acme/$winid/ctl}) 18 | size=`{echo $ctl(7) | tr -d -c 0-9} 19 | newSize=`{echo $size+$nx | bc} 20 | msg='/mnt/font/'$newfont'/'$newSize'a/font' 21 | echo font $msg | 9p write acme/$winid/ctl 22 | exit 23 | } 24 | 25 | 26 | fonts=(`{9p ls font | 9 grep -i $1}) 27 | if ( test $#fonts -eq 0 ) { 28 | 29 | echo Font $1 not found! 30 | exit 31 | } 32 | echo Select font by it exact name: 33 | for(f in $fonts) { 34 | echo $f 35 | } 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /bin/F+: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | 3 | . 9.rc 4 | . $PLAN9/lib/acme.rc 5 | 6 | nx=1 7 | if(test $#* -gt 0) { 8 | nx=$1 9 | } 10 | 11 | ctl=(`{9p read acme/$winid/ctl}) 12 | 13 | size=`{echo $ctl(7) | tr -d -c 0-9} 14 | newSize=`{echo $size+$nx | bc} 15 | newfont=`{echo $ctl(7) | tr $size $newSize} 16 | 17 | echo font $newfont | 9p write acme/$winid/ctl 18 | 19 | -------------------------------------------------------------------------------- /bin/F-: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | 3 | . 9.rc 4 | . $PLAN9/lib/acme.rc 5 | 6 | nx=1 7 | if(test $#* -gt 0) { 8 | nx=$1 9 | } 10 | 11 | ctl=(`{9p read acme/$winid/ctl}) 12 | 13 | size=`{echo $ctl(7) | tr -d -c 0-9} 14 | newSize=`{echo $size-$nx | bc} 15 | newfont=`{echo $ctl(7) | tr $size $newSize} 16 | 17 | echo font $newfont | 9p write acme/$winid/ctl 18 | -------------------------------------------------------------------------------- /bin/Fdeja: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | 3 | . 9.rc 4 | . $PLAN9/lib/acme.rc 5 | 6 | nx=1 7 | if(test $#* -gt 0) { 8 | nx=$1 9 | } 10 | 11 | ctl=(`{9p read acme/$winid/ctl}) 12 | 13 | size=`{echo $ctl(7) | tr -d -c 0-9} 14 | newfont='/mnt/font/DejaVuSansCondensed/'^$size^'a/font' 15 | 16 | echo font $newfont | 9p write acme/$winid/ctl 17 | -------------------------------------------------------------------------------- /bin/Lassist: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec L assist "$@" 3 | -------------------------------------------------------------------------------- /bin/Lcomp: -------------------------------------------------------------------------------- 1 | #!/home/gdiazlo/.local/plan9/bin/rc 2 | L comp -e | 9p write acme/`{dial unix!`{namespace}/acmefocused}/errors 3 | -------------------------------------------------------------------------------- /bin/Ldef: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec L def "$@" 3 | -------------------------------------------------------------------------------- /bin/Lfmt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec L fmt "$@" 3 | -------------------------------------------------------------------------------- /bin/Lhov: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec L hov "$@" 3 | -------------------------------------------------------------------------------- /bin/Lrefs: -------------------------------------------------------------------------------- 1 | #!/home/gdiazlo/.local/plan9/bin/rc 2 | L refs -e | 9p write acme/`{dial unix!`{namespace}/acmefocused}/errors 3 | -------------------------------------------------------------------------------- /bin/Lrn: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec L rn "$@" 3 | -------------------------------------------------------------------------------- /bin/Lsig: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec L sig "$@" 3 | -------------------------------------------------------------------------------- /bin/Lsyms: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec L syms "$@" 3 | -------------------------------------------------------------------------------- /bin/Ltype: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec L type "$@" 3 | -------------------------------------------------------------------------------- /bin/Lws: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec L ws "$@" 3 | -------------------------------------------------------------------------------- /bin/Lws+: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec L ws+ "$@" 3 | -------------------------------------------------------------------------------- /bin/Lws-: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec L ws- "$@" 3 | -------------------------------------------------------------------------------- /bin/Perl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | 3 | # aperl: 4 | # Executes perl command and alters stderr to produce Acme-friendly error messages 5 | # Created 02-JUL-1996, Luther Huffman, lutherh@stratcom.com 6 | 7 | /bin/perl $* |[2] /bin/perl -pe 's/ line (\d+)/:$1 /' >[1=2] 8 | 9 | -------------------------------------------------------------------------------- /bin/Python: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | 3 | # apython: 4 | # Executes python command and alters stderr to produce Acme-friendly error messages 5 | # Based on Perl script Created 02-JUL-1996, Luther Huffman, lutherh@stratcom.com 6 | 7 | python3 $* |[2] 9 sed 's/File "([A-Za-z_\-.\/]+)", line ([0-9]+)/\1:\2 /g' >[1=2] 8 | 9 | -------------------------------------------------------------------------------- /bin/Run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | 3 | if(! ~ $#* 1) { 4 | echo 'usage: Run title' >[1=2] 5 | exit 1 6 | } 7 | 8 | id=`{awk -v 'pat='$1 '$6 ~ pat {print $1}' <{9p read acme/index}} 9 | if(~ $#id 0) { 10 | echo 'no match for pattern' >[1=2] 11 | exit 2 12 | } 13 | if(! ~ $#id 1) { 14 | echo 'ambiguous pattern' >[1=2] 15 | exit 3 16 | } 17 | if(~ `{wc -w <{9p read acme/$id/rdsel}} 0) { 18 | echo 'no command selected' >[1=2] 19 | exit 4 20 | } 21 | #exec cat <{9p read acme/$id/rdsel} 22 | exec /usr/local/plan9/bin/rc <{9p read acme/$id/rdsel} 23 | -------------------------------------------------------------------------------- /bin/Watch: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # orignal: https://gist.github.com/mikesmullin/6401258 3 | # based on script by : Mike Smullin 4 | # license: GPLv3 5 | 6 | filepath="" 7 | if [ -z "$winid" ]; then 8 | filepath=$1 9 | shift 10 | else 11 | filepath=$( 9p read acme/$winid/tag | sed 1q | awk '{print $1}' ) 12 | fi 13 | 14 | 15 | workdir=$( dirname $filepath ) 16 | currentdir=$(pwd) 17 | 18 | cmd=$* 19 | if [ -z "$cmd" ]; then 20 | echo Usage: Watch [filepath] command 21 | exit -1 22 | fi 23 | 24 | sha=0 25 | update_sha() { 26 | sha=`/bin/ls -lR --time-style=full-iso $filepath | sha1sum` 27 | } 28 | update_sha 29 | previous_sha=$sha 30 | build() { 31 | cd $workdir 32 | $cmd 33 | cd $currentdir 34 | } 35 | compare() { 36 | update_sha 37 | if [[ $sha != $previous_sha ]] ; then 38 | build 39 | previous_sha=$sha 40 | fi 41 | } 42 | trap build SIGINT 43 | trap exit SIGQUIT 44 | 45 | while true; do 46 | compare 47 | sleep 1 48 | done 49 | 50 | -------------------------------------------------------------------------------- /bin/acal: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # A rewrite based on https://github.com/marvinthepa/mutt-ical 4 | 5 | import vobject 6 | import tempfile, time 7 | import os, sys 8 | import warnings 9 | from datetime import datetime 10 | from getopt import gnu_getopt as getopt 11 | 12 | usage=""" 13 | It reads an ical event invitation from stdin and generates 14 | an answer accepting, declining or tentatively accepting the event 15 | invitation. The invitation is tentatively accepted by default. 16 | 17 | It reads upasname environment variable by default, but other one 18 | can be indicated, ignoring the environment variable. 19 | 20 | It will output the nedmail command needed to reply to the message 21 | including the ical event answered. 22 | usage: 23 | %s [OPTIONS] [-e your@email.address] 24 | OPTIONS: 25 | -p print 26 | -a accept 27 | -d decline 28 | -t tentatively accept 29 | (print is default, last one wins) 30 | """ % sys.argv[0] 31 | 32 | def read_ics(): 33 | try: 34 | with warnings.catch_warnings(): 35 | warnings.simplefilter("ignore") 36 | invitation = vobject.readOne(sys.stdin, ignoreUnreadable=True) 37 | except AttributeError: 38 | invitation = vobject.readOne(sys.stdin, ignoreUnreadable=True) 39 | return invitation 40 | 41 | class Answer: 42 | def __init__(self, invitation, resp, email): 43 | # create 44 | ans = vobject.newFromBehavior('vcalendar') 45 | ans.add('method') 46 | ans.method.value = "REPLY" 47 | ans.add('vevent') 48 | 49 | for i in ["uid", "summary", "dtstart", "dtend", "organizer"]: 50 | if i in invitation.vevent.contents: 51 | ans.vevent.add( invitation.vevent.contents[i][0] ) 52 | 53 | # new timestamp 54 | ans.vevent.add('dtstamp') 55 | ans.vevent.dtstamp.value = datetime.utcnow().replace(tzinfo = invitation.vevent.dtstamp.value.tzinfo) 56 | 57 | ans.vevent.add('attendee') 58 | ans.vevent.attendee_list.pop() 59 | 60 | if 'attendee' in invitation.vevent.contents: 61 | atts = invitation.vevent.contents['attendee'] 62 | for a in atts: 63 | if self._get_email(a) == email: 64 | ans.vevent.attendee_list.append(self._set_resp(a,resp)) 65 | 66 | self.ans = ans 67 | 68 | @staticmethod 69 | def _get_email(att): 70 | if hasattr(att,'EMAIL_param'): 71 | return att.EMAIL_param 72 | else: 73 | return att.value.split(':')[1] 74 | 75 | @staticmethod 76 | def _set_resp(att, resp): 77 | att.params['PARTSTAT'] = [resp] 78 | for i in ["RSVP","ROLE","X-NUM-GUESTS","CUTYPE"]: 79 | if i in att.params: 80 | del att.params[i] 81 | return att 82 | 83 | def write(self): 84 | tempdir = tempfile.mkdtemp() 85 | icsfile = tempdir+"/event-reply.ics" 86 | with open(icsfile,"w") as f: 87 | f.write(self.ans.serialize()) 88 | return icsfile 89 | 90 | class Invitation: 91 | def __init__(self,ical): 92 | self.ics = ical 93 | contents = ical.vevent.contents 94 | self.title = contents['summary'][0].value 95 | if 'organizer' in ical.vevent.contents: 96 | if hasattr(ical.vevent.organizer,'EMAIL_param'): 97 | self.sender = ical.vevent.organizer.EMAIL_param 98 | else: 99 | self.sender = ical.vevent.organizer.value.split(':')[1] 100 | 101 | if 'description' in contents: 102 | self.desc = contents['description'][0].value 103 | 104 | if 'dtstart' in contents: 105 | self.start = contents['dtstart'][0].value.strftime("%m/%d/%Y, %H:%M:%S") 106 | 107 | if 'dtend' in contents: 108 | self.end = contents['dtend'][0].value.strftime("%m/%d/%Y, %H:%M:%S") 109 | 110 | if 'attendee' in contents: 111 | self.attendees = contents['attendee'] 112 | 113 | @staticmethod 114 | def _attendee(a): 115 | if hasattr(a, 'EMAIL_param'): 116 | att_mail = a.CN_param 117 | att_cn = a.EMAIL_param 118 | else: 119 | att_mail = a.value.split(':')[1] 120 | att_cn = a.value.split(':')[1] 121 | if a.CN_param: 122 | att_cn = a.CN_param 123 | 124 | return "\t" + att_cn + " <" + att_mail + ">" 125 | 126 | def __str__(self): 127 | r = map(self._attendee, self.attendees) 128 | to = "\n".join(r) 129 | return ("From: %s\n" 130 | "To:\n%s\n" 131 | "Title: %s\n" 132 | "When: from %s to %s\n" 133 | "Description:\n %s\n") % (self.sender, to, self.title, self.start, self.end, self.desc) 134 | 135 | if __name__=="__main__": 136 | email = os.environ['upasname'] 137 | resp = 'TENTATIVE' 138 | opts, args=getopt(sys.argv[1:],":epadt") 139 | 140 | invitation = Invitation(read_ics()) 141 | 142 | for opt,arg in opts: 143 | if opt == '-e': 144 | email = arg 145 | if opt == '-p': 146 | print(invitation) 147 | sys.exit() 148 | if opt == '-a': 149 | resp = 'ACCEPTED' 150 | if opt == '-d': 151 | resp = 'DECLINED' 152 | if opt == '-t': 153 | resp = 'TENTATIVE' 154 | 155 | ans = Answer(invitation.ics, resp, email) 156 | 157 | icsfile, tempdir = ans.write() 158 | 159 | print('r -a'+icsfile) 160 | 161 | -------------------------------------------------------------------------------- /bin/acme: -------------------------------------------------------------------------------- 1 | #!/usr/local/plan9/bin/rc 2 | 3 | . $home/lib/profile 4 | 5 | if(test -r $home/acme.dump) { 6 | $PLAN9/bin/acme -a -c 1 -f $hidpifont -F $hidpifixedfont -l $home/acme.dump $* 7 | } 8 | if not { 9 | $PLAN9/bin/acme -a -c 1 -f $hidpifont -F $hidpifixedfont $* 10 | } 11 | 12 | -------------------------------------------------------------------------------- /bin/cam: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ]; then 4 | cam=0 5 | else 6 | cam=$1 7 | fi 8 | 9 | gphoto2 --wait-event=3s --stdout --capture-movie | ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420p -threads 0 -f v4l2 /dev/video$cam 10 | -------------------------------------------------------------------------------- /bin/emoji: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | IFS=" " 3 | while read -a emoji 4 | do 5 | unicode ${emoji[0]} 6 | done << EOF 7 | 1F601 \xF0\x9F\x98\x81 GRINNING FACE WITH SMILING EYES 8 | 1F602 \xF0\x9F\x98\x82 FACE WITH TEARS OF JOY 9 | 1F603 \xF0\x9F\x98\x83 SMILING FACE WITH OPEN MOTH 10 | 1F604 \xF0\x9F\x98\x84 SMILING FACE WITH OPEN MOTH AND SMILIN 11 | 1F605 \xF0\x9F\x98\x85 SMILING FACE WITH OPEN MOTH AND COLD S 12 | 1F606 \xF0\x9F\x98\x86 SMILING FACE WITH OPEN MOTH AND TIGHTLY-CLOSED EYES 13 | 1F609 \xF0\x9F\x98\x89 WINKING FACE 14 | 1F60A \xF0\x9F\x98\x8A SMILING FACE WITH SMILING EYES 15 | 1F60B \xF0\x9F\x98\x8B FACE SAVORING DELICIOS FOOD 16 | 1F60C \xF0\x9F\x98\x8C RELIEVED FACE 17 | 1F60D \xF0\x9F\x98\x8D SMILING FACE WITH HEART-SHAPED EYES 18 | 1F60F \xF0\x9F\x98\x8F SMIRKING FACE 19 | 1F612 \xF0\x9F\x98\x92 NAMSED FACE 20 | 1F613 \xF0\x9F\x98\x93 FACE WITH COLD SWEAT 21 | 1F614 \xF0\x9F\x98\x94 PENSIVE FACE 22 | 1F616 \xF0\x9F\x98\x96 CONFONDED FACE 23 | 1F618 \xF0\x9F\x98\x98 FACE THROWING A KISS 24 | 1F61A \xF0\x9F\x98\x9A KISSING FACE WITH CLOSED EYES 25 | 1F61C \xF0\x9F\x98\x9C FACE WITH STCK-OT TONGE AND WINKING EYE 26 | 1F61D \xF0\x9F\x98\x9D FACE WITH STCK-OT TONGE AND TIGHTLY-CLOSED EYES 27 | 1F61E \xF0\x9F\x98\x9E DISAPPOINTED FACE 28 | 1F620 \xF0\x9F\x98\xA0 ANGRY FACE 29 | 1F621 \xF0\x9F\x98\xA1 POTING FACE 30 | 1F622 \xF0\x9F\x98\xA2 CRYING FACE 31 | 1F623 \xF0\x9F\x98\xA3 PERSEVERING FACE 32 | 1F624 \xF0\x9F\x98\xA4 FACE WITH LOOK OF TRIMPH 33 | 1F625 \xF0\x9F\x98\xA5 DISAPPOINTED BT RELIEVED FACE 34 | 1F628 \xF0\x9F\x98\xA8 FEARFL FACE 35 | 1F629 \xF0\x9F\x98\xA9 WEARY FACE 36 | 1F62A \xF0\x9F\x98\xAA SLEEPY FACE 37 | 1F62B \xF0\x9F\x98\xAB TIRED FACE 38 | 1F62D \xF0\x9F\x98\xAD LODLY CRYING FACE 39 | 1F630 \xF0\x9F\x98\xB0 FACE WITH OPEN MOTH AND COLD SWEAT 40 | 1F631 \xF0\x9F\x98\xB1 FACE SCREAMING IN FEAR 41 | 1F632 \xF0\x9F\x98\xB2 ASTONISHED FACE 42 | 1F633 \xF0\x9F\x98\xB3 FLSHED FACE 43 | 1F635 \xF0\x9F\x98\xB5 DIZZY FACE 44 | 1F637 \xF0\x9F\x98\xB7 FACE WITH MEDICAL MASK 45 | 1F638 \xF0\x9F\x98\xB8 GRINNING CAT FACE WITH SMILING EYES 46 | 1F639 \xF0\x9F\x98\xB9 CAT FACE WITH TEARS OF JOY 47 | 1F63A \xF0\x9F\x98\xBA SMILING CAT FACE WITH OPEN MOTH 48 | 1F63B \xF0\x9F\x98\xBB SMILING CAT FACE WITH HEART-SHAPED EYES 49 | 1F63C \xF0\x9F\x98\xBC CAT FACE WITH WRY SMILE 50 | 1F63D \xF0\x9F\x98\xBD KISSING CAT FACE WITH CLOSED EYES 51 | 1F63E \xF0\x9F\x98\xBE POTING CAT FACE 52 | 1F63F \xF0\x9F\x98\xBF CRYING CAT FACE 53 | 1F640 \xF0\x9F\x99\x80 WEARY CAT FACE 54 | 1F645 \xF0\x9F\x99\x85 FACE WITH NO GOOD GESTRE 55 | 1F646 \xF0\x9F\x99\x86 FACE WITH OK GESTRE 56 | 1F647 \xF0\x9F\x99\x87 PERSON BOWING DEEPLY 57 | 1F648 \xF0\x9F\x99\x88 SEE-NO-EVIL MONKEY 58 | 1F649 \xF0\x9F\x99\x89 HEAR-NO-EVIL MONKEY 59 | 1F64A \xF0\x9F\x99\x8A SPEAK-NO-EVIL MONKEY 60 | 1F64B \xF0\x9F\x99\x8B HAPPY PERSON RAISING ONE HAND 61 | 1F64C \xF0\x9F\x99\x8C PERSON RAISING BOTH HANDS IN CELEBRATION 62 | 1F64D \xF0\x9F\x99\x8D PERSON FROWNING 63 | 1F64E \xF0\x9F\x99\x8E PERSON WITH POTING FACE 64 | 1F64F \xF0\x9F\x99\x8F PERSON WITH FOLDED HANDS 65 | EOF 66 | 67 | -------------------------------------------------------------------------------- /bin/helloml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S ocaml unix.cma -I +unix 2 | 3 | let () = 4 | Printf.printf "Hello, world!\n" 5 | -------------------------------------------------------------------------------- /bin/ipso: -------------------------------------------------------------------------------- 1 | #!/usr/local/plan9/bin/rc 2 | 3 | . 9.rc 4 | name = secstore 5 | get = secstoreget 6 | put = secstoreput 7 | edit = no 8 | load = no 9 | flush = no 10 | 11 | fn secstoreget{ 12 | secstore -i -g $1 <_password 13 | } 14 | 15 | fn secstoreput{ 16 | secstore -i -p $1 <_password 17 | } 18 | 19 | fn aesget{ 20 | if(! ~ $1 /*){ 21 | echo >[1=2] ipso: aescbc requires fully qualified pathname 22 | exit usage 23 | } 24 | aescbc -i -d < $1 > `{basename $1} <[3] _password 25 | } 26 | 27 | fn aesput{ 28 | aescbc -i -e > $1 < `{basename $1} <[3] _password 29 | } 30 | 31 | fn editedfiles{ 32 | if(~ $get aesget){ 33 | for(i in $files) 34 | if(ls -tr | sed '1,/^_timestamp$/d' | grep -s '^'^`{basename $i}^'$') 35 | echo $i 36 | } 37 | if not 38 | ls -tr | sed '1,/^_timestamp$/d' 39 | } 40 | 41 | while(~ $1 -*){ 42 | switch($1){ 43 | case -a 44 | name = aescbc 45 | get = aesget 46 | put = aesput 47 | case -f 48 | flush = yes 49 | case -e 50 | edit = yes 51 | case -l 52 | load = yes 53 | case * 54 | echo >[2=1] 'usage: ipso [-a -f -e -l] [-s] [file ...]' 55 | exit usage 56 | } 57 | shift 58 | } 59 | 60 | if(~ $flush no && ~ $edit no && ~ $load no){ 61 | edit = yes 62 | if(~ factotum $*){ 63 | load = yes 64 | flush = yes 65 | } 66 | } 67 | 68 | if(~ $flush yes && ~ $edit no && ~ $load no){ 69 | echo flushing old keys 70 | echo delkey | 9p write factotum/ctl 71 | exit 0 72 | } 73 | 74 | if(~ $get aesget && ~ $#* 0){ 75 | echo >[2=1] ipso: must specify a fully qualified file name for aescbc '(-a)' 76 | exit usage 77 | } 78 | 79 | user=`{whoami} 80 | cd $NAMESPACE 81 | echo Wroking in $NAMESPACE 82 | mkdir -p ipso.$user 83 | chmod 700 ipso.$user || exit $status 84 | cd ipso.$user 85 | dir=`{pwd} 86 | dir=$"dir 87 | 88 | fn sigexit { 89 | rm -rf $dir 90 | } 91 | 92 | if ( ~ $edit yes ) echo ' 93 | Warning: The editor will display the secret contents of 94 | your '$name' files in the clear, and they will 95 | be stored temporarily in '^$dir^' 96 | in the clear, along with your password. 97 | ' 98 | 99 | # get password and remember it 100 | readcons -s $name^' password' >_password 101 | 102 | # get list of files 103 | if(~ $#* 0){ 104 | if(! secstore -G . -i < _password > _listing){ 105 | echo 'secstore read failed - bad password?' 106 | sleep 2 107 | exit password 108 | } 109 | files=`{sed 's/[ ]+.*//' _listing} 110 | } 111 | if not 112 | files = $* 113 | 114 | # copy the files to local ramfs 115 | for(i in $files){ 116 | if(! $get $i){ 117 | echo $name ' read failed - bad password?' 118 | sleep 2 119 | exit password 120 | } 121 | } 122 | sleep 2; date > _timestamp # so we can find which files have been edited. 123 | 124 | # edit the files 125 | if(~ $edit yes){ 126 | B `{for(i in $files) basename $i} 127 | readcons 'type enter when finished editing' >/dev/null 128 | } 129 | if(~ $flush yes ){ 130 | echo flushing old keys 131 | echo delkey | 9p write factotum/ctl 132 | } 133 | if(~ $load yes){ 134 | echo loading factotum keys 135 | if (~ factotum $files) cat factotum | 9p write -l factotum/ctl 136 | } 137 | 138 | # copy the files back 139 | for(i in `{editedfiles}){ 140 | prompt='copy '''^`{basename $i}^''' back? [y/n/x]' 141 | switch(`{readcons $prompt}){ 142 | case [yY]* 143 | if(! $put $i){ 144 | echo $name ' read failed - bad password?' 145 | sleep 2 146 | exit password 147 | } 148 | echo ''''$i'''' copied to $name 149 | if(~ $i factotum && ! ~ $load yes){ # do not do it twice 150 | cat $i | 9p write -l factotum/ctl 151 | } 152 | case [xXqQ]* 153 | exit 154 | case [nN]* * 155 | echo ''''$i'''' skipped 156 | } 157 | } 158 | 159 | exit '' 160 | -------------------------------------------------------------------------------- /bin/readmail: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | # 3 | # Read email using nedmail for the given account. 4 | # The account is specified by the domain in user@domain.com 5 | # and it needs to be present in factotum as imap credentials. 6 | # 7 | path=($PLAN9/bin $path) 8 | 9 | nl=' 10 | ' 11 | fn srvargs { 12 | ifs=$nl 13 | switch($#*){ 14 | case 0 15 | raw=`{9p read factotum/ctl | 9 sed 's/([a-z]+)=//g' | awk '{print $4 " " $5 " " $6 }' | grep imap} 16 | case 1 17 | raw=`{9p read factotum/ctl | 9 sed 's/([a-z]+)=//g' | awk '{print $4 " " $5 " " $6 }' | grep imap | grep $1} 18 | } 19 | for(s in $raw) { 20 | ifs=' ' sa=`{echo -n $s} 21 | d=`{echo -n $sa(3) | sed 's/[a-zA-Z0-9_+.\-]+@([a-zA-Z0-9_+\-]+).([a-zA-Z0-9_+.\-]*)/\1/g' | tr -d $nl} 22 | echo $d $sa(3) $sa(1) 23 | } 24 | } 25 | 26 | fn usage { 27 | ifs=$nl 28 | servers=`{srvargs} 29 | switch($#servers){ 30 | case 0 31 | echo 'Fill factotum with imap servers credentials' 32 | exit 33 | case * 34 | echo 'usage: ' 35 | echo ' readmail [nedmail options]' 36 | echo 'where domain can be one of:' 37 | for(s in $servers) { echo $s | awk '{print $1}'} 38 | } 39 | } 40 | 41 | switch($#*){ 42 | case 0 43 | usage 44 | exit 45 | case * 46 | dom=$1 47 | shift 48 | } 49 | 50 | ifs=$nl 51 | servers=`{srvargs $dom} 52 | ifs=' ' sa=`{echo -n $servers(1)} 53 | upasname=$sa(2) 54 | server=$sa(3) 55 | 56 | if(! test -r $NAMESPACE/mail.$dom) { 57 | mailfs -s mail.$dom -t -u $upasname $server 58 | } 59 | 60 | echo $dom as $upasname 61 | exec nedmail -S mail.$dom $* 62 | 63 | -------------------------------------------------------------------------------- /bin/riostart: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | 3 | if( test -x `{which xbindkeys}) { 4 | exec xbindkeys -f $home/.config/acme/desktop/xbindkeysrc & 5 | } 6 | 7 | #exec 9 rio -font -*-lucida-medium-r-normal-sans-17-*-100-100-*-*-*-* -term 9term -virtuals 4 & 8 | exec 9 rio -font 'Fira Sans 12' -term 9term -virtuals 4 & 9 | 10 | if( test -x `{which compton}) { 11 | exec compton & 12 | } 13 | 14 | if( test -x `{which dunst}) { 15 | exec dunst -conf $home/.config/acme/desktop/dunstrc & 16 | } 17 | 18 | exec winwatch -f $font -s -W 150x800 19 | -------------------------------------------------------------------------------- /bin/screenshot: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | selection=$(hacksaw -f "-i %i -g %g") 4 | shotgun $selection - | xclip -t 'image/png' -selection clipboard 5 | -------------------------------------------------------------------------------- /desktop/9term.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Comment[en_US]=It stars a plan9port session with rc -l 3 | Comment=It stars a plan9port session with rc -l 4 | Exec=/usr/local/plan9/bin/rc -c 'echo exec /usr/local/plan9/bin/9term rc | /usr/local/plan9/bin/rc -l' 5 | GenericName[en_US]=plan9port terminal\s 6 | GenericName=plan9port terminal\s 7 | Icon=/usr/local/plan9/dist/glendacircle.png 8 | MimeType= 9 | Name[en_US]=9term 10 | Name=9term 11 | Path= 12 | StartupNotify=true 13 | Terminal=false 14 | TerminalOptions= 15 | Type=Application 16 | X-DBUS-ServiceName= 17 | X-DBUS-StartupType=none 18 | X-KDE-SubstituteUID=false 19 | X-KDE-Username= 20 | -------------------------------------------------------------------------------- /desktop/Xresources: -------------------------------------------------------------------------------- 1 | xterm*faceName: DEC Terminal Modern:style=Regular 2 | xterm*boldFont: DEC Terminal Modern:style=Bold 3 | xterm*renderFont: true 4 | xterm*faceSize: 15 5 | 6 | xterm*background: #262626 7 | xterm*foreground: #fcc000 8 | *cursorColor: #ff0000 9 | ! dark gray 10 | xterm*color0: #161616 11 | ! red 12 | xterm*color1: #8d8d8d 13 | ! green 14 | xterm*color2: #198038 15 | ! yellow 16 | xterm*color3: #8a3ffc 17 | ! blue 18 | xterm*color4: #0f62fe 19 | ! magenta 20 | xterm*color5: #d12771 21 | ! teal 22 | xterm*color6: #004144 23 | ! gray 24 | xterm*color7: #f4f4f4 25 | ! black 26 | xterm*color8: #000000 27 | ! dark red 28 | xterm*color9: #750e13 29 | ! dark green 30 | xterm*color10: #044317 31 | ! dark yellow 32 | xterm*color11: #491d8b 33 | ! dark blue 34 | xterm*color12: #002d9c 35 | ! dark magenta 36 | xterm*color13: #740937 37 | ! dark teal 38 | xterm*color14: #007d79 39 | ! white 40 | xterm*color15: #161616 41 | 42 | xterm*faceSize1: 6 43 | xterm*faceSize2: 8 44 | xterm*faceSize3: 10 45 | xterm*faceSize4: 12 46 | xterm*faceSize5: 16 47 | xterm*faceSize6: 24 48 | 49 | xterm*utf8: true 50 | xterm*vt100*geometry: 80x25 51 | xterm*saveLines: 16384 52 | xterm*loginShell: true 53 | xterm*charClass: 33:48,35:48,37:48,43:48,45-47:48,64:48,95:48,126:48 54 | xterm*termName: xterm-color 55 | !xterm*locale: true 56 | xterm*vbell: True 57 | xterm.underlineURLs: true 58 | xterm*inheritPixmap: true 59 | xterm*dynamicColors: true 60 | 61 | xterm*scrollBar: on 62 | xterm*multiScroll: on 63 | xterm*jumpScroll: on 64 | 65 | xterm*decTerminalID: vt340 66 | xterm*numColorRegisters: 256 67 | xterm*maxGraphicSize: 2560x1440 68 | xterm*disallowedWindowOps: 20,21,Setxprop 69 | 70 | xterm*VT100.Translations: #override \ 71 | Ctrl minus: smaller-vt-font() \n\ 72 | Ctrl plus: larger-vt-font() \n\ 73 | Ctrl 0: set-vt-font(d) 74 | 75 | Xft.dpi: 200 76 | 77 | Xft.autohint: 0 78 | Xft.lcdfilter: lcddefault 79 | Xft.hintstyle: hintslight 80 | Xft.hinting: 1 81 | Xft.antialias: 1 82 | Xft.rgba: rgb 83 | Xcursor.size: 32 84 | 85 | -------------------------------------------------------------------------------- /desktop/acme.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Comment[en_US]=starts acme using a plan9port session 3 | Comment=starts acme using a plan9port session 4 | Exec=/usr/local/plan9/bin/rc -c 'echo exec acme | /usr/local/plan9/bin/rc -l' 5 | GenericName[en_US]=acme editor on a plan9port session 6 | GenericName=acme editor on a plan9port session 7 | Icon=/usr/local/plan9/dist/spaceglenda100.png 8 | MimeType= 9 | Name[en_US]=acme 10 | Name=acme 11 | Path= 12 | StartupNotify=true 13 | Terminal=false 14 | TerminalOptions= 15 | Type=Application 16 | X-DBUS-ServiceName= 17 | X-DBUS-StartupType= 18 | X-KDE-SubstituteUID=false 19 | X-KDE-Username= 20 | -------------------------------------------------------------------------------- /desktop/alacritty.yml: -------------------------------------------------------------------------------- 1 | # Configuration for Alacritty, the GPU enhanced terminal emulator. 2 | 3 | # Any items in the `env` entry below will be added as 4 | # environment variables. Some entries may override variables 5 | # set by alacritty itself. 6 | #env: 7 | # TERM variable 8 | # 9 | # This value is used to set the `$TERM` environment variable for 10 | # each instance of Alacritty. If it is not present, alacritty will 11 | # check the local terminfo database and use `alacritty` if it is 12 | # available, otherwise `xterm-256color` is used. 13 | #TERM: alacritty 14 | 15 | #window: 16 | # Window dimensions (changes require restart) 17 | # 18 | # Specified in number of columns/lines, not pixels. 19 | # If both are `0`, this setting is ignored. 20 | #dimensions: 21 | # columns: 0 22 | # lines: 0 23 | 24 | # Window position (changes require restart) 25 | # 26 | # Specified in number of pixels. 27 | # If the position is not set, the window manager will handle the placement. 28 | #position: 29 | # x: 0 30 | # y: 0 31 | 32 | # Window padding (changes require restart) 33 | # 34 | # Blank space added around the window in pixels. This padding is scaled 35 | # by DPI and the specified value is always added at both opposing sides. 36 | #padding: 37 | # x: 0 38 | # y: 0 39 | 40 | # Spread additional padding evenly around the terminal content. 41 | #dynamic_padding: false 42 | 43 | # Window decorations 44 | # 45 | # Values for `decorations`: 46 | # - full: Borders and title bar 47 | # - none: Neither borders nor title bar 48 | # 49 | # Values for `decorations` (macOS only): 50 | # - transparent: Title bar, transparent background and title bar buttons 51 | # - buttonless: Title bar, transparent background, but no title bar buttons 52 | #decorations: full 53 | 54 | # Startup Mode (changes require restart) 55 | # 56 | # Values for `startup_mode`: 57 | # - Windowed 58 | # - Maximized 59 | # - Fullscreen 60 | # 61 | # Values for `startup_mode` (macOS only): 62 | # - SimpleFullscreen 63 | #startup_mode: Windowed 64 | 65 | # Window title 66 | #title: Alacritty 67 | 68 | # Allow terminal applications to change Alacritty's window title. 69 | #dynamic_title: true 70 | 71 | # Window class (Linux/BSD only): 72 | #class: 73 | # Application instance name 74 | #instance: Alacritty 75 | # General application class 76 | #general: Alacritty 77 | 78 | # GTK theme variant (Linux/BSD only) 79 | # 80 | # Override the variant of the GTK theme. Commonly supported values are `dark` and `light`. 81 | # Set this to `None` to use the default theme variant. 82 | #gtk_theme_variant: None 83 | 84 | #scrolling: 85 | # Maximum number of lines in the scrollback buffer. 86 | # Specifying '0' will disable scrolling. 87 | #history: 10000 88 | 89 | # Scrolling distance multiplier. 90 | #multiplier: 3 91 | 92 | # Font configuration 93 | font: 94 | # Normal (roman) font face 95 | normal: 96 | # Font family 97 | # 98 | # Default: 99 | # - (macOS) Menlo 100 | # - (Linux/BSD) monospace 101 | # - (Windows) Consolas 102 | #family: IBM Plex Mono 103 | family: Iosevka 104 | 105 | # The `style` can be specified to pick a specific face. 106 | style: Medium 107 | 108 | # Bold font face 109 | #bold: 110 | # Font family 111 | # 112 | # If the bold family is not specified, it will fall back to the 113 | # value specified for the normal font. 114 | #family: monospace 115 | 116 | # The `style` can be specified to pick a specific face. 117 | #style: Bold 118 | 119 | # Italic font face 120 | #italic: 121 | # Font family 122 | # 123 | # If the italic family is not specified, it will fall back to the 124 | # value specified for the normal font. 125 | #family: monospace 126 | 127 | # The `style` can be specified to pick a specific face. 128 | #style: Italic 129 | 130 | # Bold italic font face 131 | #bold_italic: 132 | # Font family 133 | # 134 | # If the bold italic family is not specified, it will fall back to the 135 | # value specified for the normal font. 136 | #family: monospace 137 | 138 | # The `style` can be specified to pick a specific face. 139 | #style: Bold Italic 140 | 141 | # Point size 142 | size: 16.0 143 | 144 | # Offset is the extra space around each character. `offset.y` can be thought of 145 | # as modifying the line spacing, and `offset.x` as modifying the letter spacing. 146 | #offset: 147 | # x: 0 148 | # y: 0 149 | 150 | # Glyph offset determines the locations of the glyphs within their cells with 151 | # the default being at the bottom. Increasing `x` moves the glyph to the right, 152 | # increasing `y` moves the glyph upward.Terminus (TTF) 153 | #glyph_offset: 154 | # x: 0 155 | # y: 0 156 | 157 | # Thin stroke font rendering (macOS only) 158 | # 159 | # Thin strokes are suitable for retina displays, but for non-retina screens 160 | # it is recommended to set `use_thin_strokes` to `false`. 161 | #use_thin_strokes: true 162 | 163 | # If `true`, bold text is drawn using the bright color variants. 164 | #draw_bold_text_with_bright_colors: false 165 | 166 | # Colors (Tomorrow Night) 167 | colors: 168 | # Default colors 169 | primary: 170 | background: '#161616' 171 | #foreground: '#f4f4f4' 172 | foreground: '#ffc000' 173 | 174 | # Cursor colors 175 | # 176 | # Colors which should be used to draw the terminal cursor. 177 | # 178 | # Allowed values are CellForeground and CellBackground, which reference the 179 | # affected cell, or hexadecimal colors like #ff00ff. 180 | cursor: 181 | text: CellBackground 182 | cursor: CellForeground 183 | 184 | # Vi mode cursor colors 185 | # 186 | # Colors for the cursor when the vi mode is active. 187 | # 188 | # Allowed values are CellForeground and CellBackground, which reference the 189 | # affected cell, or hexadecimal colors like #ff00ff. 190 | vi_mode_cursor: 191 | text: CellBackground 192 | cursor: CellForeground 193 | 194 | # Selection colors 195 | # 196 | # Colors which should be used to draw the selection area. 197 | # 198 | # Allowed values are CellForeground and CellBackground, which reference the 199 | # affected cell, or hexadecimal colors like #ff00ff. 200 | selection: 201 | text: CellBackground 202 | background: CellForeground 203 | 204 | # Search colors 205 | # 206 | # Colors used for the search bar and match highlighting. 207 | search: 208 | # Allowed values are CellForeground and CellBackground, which reference the 209 | # affected cell, or hexadecimal colors like #ff00ff. 210 | matches: 211 | #foreground: '#000000' 212 | foreground: '#ffc000' 213 | background: '#ffffff' 214 | 215 | #bar: 216 | # background: '#c5c8c6' 217 | # foreground: '#1d1f21' 218 | 219 | # Normal colors 220 | normal: 221 | black: '#161616' 222 | red: '#da1e28' 223 | green: '#198038' 224 | yellow: '#8a3ffc' 225 | blue: '#0f62fe' 226 | magenta: '#d12771' 227 | cyan: '#0072c3' 228 | white: '#f4f4f4' 229 | 230 | # Bright colors 231 | bright: 232 | black: '#000000' 233 | red: '#750e13' 234 | green: '#044317' 235 | yellow: '#491d8b' 236 | blue: '#002d9c' 237 | magenta: '#740937' 238 | cyan: '#003a6d' 239 | white: '#ffffff' 240 | 241 | # Dim colors 242 | # 243 | # If the dim colors are not set, they will be calculated automatically based 244 | # on the `normal` colors. 245 | dim: 246 | black: '#8d8d8d' 247 | red: '#ffb3b8' 248 | green: '#6fdc8c' 249 | yellow: '#d4bbff' 250 | blue: '#a6c8ff' 251 | magenta: '#ffafd2' 252 | cyan: '#82cfff' 253 | white: '#e0e0e0' 254 | 255 | # Indexed Colors 256 | # 257 | # The indexed colors include all colors from 16 to 256. 258 | # When these are not set, they're filled with sensible defaults. 259 | # 260 | # Example: 261 | # `- { index: 16, color: '#ff00ff' }` 262 | # 263 | #indexed_colors: [] 264 | 265 | # Bell 266 | # 267 | # The bell is rung every time the BEL control character is received. 268 | #bell: 269 | # Visual Bell Animation 270 | # 271 | # Animation effect for flashing the screen when the visual bell is rung. 272 | # 273 | # Values for `animation`: 274 | # - Ease 275 | # - EaseOut 276 | # - EaseOutSine 277 | # - EaseOutQuad 278 | # - EaseOutCubic 279 | # - EaseOutQuart 280 | # - EaseOutQuint 281 | # - EaseOutExpo 282 | # - EaseOutCirc 283 | # - Linear 284 | #animation: EaseOutExpo 285 | 286 | # Duration of the visual bell flash. A `duration` of `0` will disable the 287 | # visual bell animation. 288 | #duration: 0 289 | 290 | # Visual bell animation color. 291 | #color: '#ffffff' 292 | 293 | # Bell Command 294 | # 295 | # This program is executed whenever the bell is rung. 296 | # 297 | # When set to `command: None`, no command will be executed. 298 | # 299 | # Example: 300 | # command: 301 | # program: notify-send 302 | # args: ["Hello, World!"] 303 | # 304 | #command: None 305 | 306 | # Background opacity 307 | # 308 | # Window opacity as a floating point number from `0.0` to `1.0`. 309 | # The value `0.0` is completely transparent and `1.0` is opaque. 310 | #background_opacity: 1.0 311 | 312 | #selection: 313 | #semantic_escape_chars: ",│`|:\"' ()[]{}<>\t" 314 | 315 | # When set to `true`, selected text will be copied to the primary clipboard. 316 | #save_to_clipboard: false 317 | 318 | #cursor: 319 | # Cursor style 320 | # 321 | # Values for `style`: 322 | # - ▇ Block 323 | # - _ Underline 324 | # - | Beam 325 | #style: Block 326 | 327 | # Vi mode cursor style 328 | # 329 | # If the vi mode cursor style is `None` or not specified, it will fall back to 330 | # the style of the active value of the normal cursor. 331 | # 332 | # See `cursor.style` for available options. 333 | #vi_mode_style: None 334 | 335 | # If this is `true`, the cursor will be rendered as a hollow box when the 336 | # window is not focused. 337 | #unfocused_hollow: true 338 | 339 | # Thickness of the cursor relative to the cell width as floating point number 340 | # from `0.0` to `1.0`. 341 | #thickness: 0.15 342 | 343 | # Live config reload (changes require restart) 344 | #live_config_reload: true 345 | 346 | # Shell 347 | # 348 | # You can set `shell.program` to the path of your favorite shell, e.g. `/bin/fish`. 349 | # Entries in `shell.args` are passed unmodified as arguments to the shell. 350 | # 351 | # Default: 352 | # - (macOS) /bin/bash --login 353 | # - (Linux/BSD) user login shell 354 | # - (Windows) powershell 355 | #shell: 356 | # program: /bin/bash 357 | # args: 358 | # - --login 359 | 360 | # Startup directory 361 | # 362 | # Directory the shell is started in. If this is unset, or `None`, the working 363 | # directory of the parent process will be used. 364 | #working_directory: None 365 | 366 | # WinPTY backend (Windows only) 367 | # 368 | # Alacritty defaults to using the newer ConPTY backend if it is available, 369 | # since it resolves a lot of bugs and is quite a bit faster. If it is not 370 | # available, the WinPTY backend will be used instead. 371 | # 372 | # Setting this option to `true` makes Alacritty use the legacy WinPTY backend, 373 | # even if the ConPTY backend is available. 374 | #winpty_backend: false 375 | 376 | # Send ESC (\x1b) before characters when alt is pressed. 377 | #alt_send_esc: true 378 | 379 | #mouse: 380 | # Click settings 381 | # 382 | # The `double_click` and `triple_click` settings control the time 383 | # alacritty should wait for accepting multiple clicks as one double 384 | # or triple click. 385 | #double_click: { threshold: 300 } 386 | #triple_click: { threshold: 300 } 387 | 388 | # If this is `true`, the cursor is temporarily hidden when typing. 389 | #hide_when_typing: false 390 | 391 | #url: 392 | # URL launcher 393 | # 394 | # This program is executed when clicking on a text which is recognized as a URL. 395 | # The URL is always added to the command as the last parameter. 396 | # 397 | # When set to `launcher: None`, URL launching will be disabled completely. 398 | # 399 | # Default: 400 | # - (macOS) open 401 | # - (Linux/BSD) xdg-open 402 | # - (Windows) explorer 403 | #launcher: 404 | # program: xdg-open 405 | # args: [] 406 | 407 | # URL modifiers 408 | # 409 | # These are the modifiers that need to be held down for opening URLs when clicking 410 | # on them. The available modifiers are documented in the key binding section. 411 | #modifiers: None 412 | 413 | # Mouse bindings 414 | # 415 | # Mouse bindings are specified as a list of objects, much like the key 416 | # bindings further below. 417 | # 418 | # To trigger mouse bindings when an application running within Alacritty captures the mouse, the 419 | # `Shift` modifier is automatically added as a requirement. 420 | # 421 | # Each mouse binding will specify a: 422 | # 423 | # - `mouse`: 424 | # 425 | # - Middle 426 | # - Left 427 | # - Right 428 | # - Numeric identifier such as `5` 429 | # 430 | # - `action` (see key bindings) 431 | # 432 | # And optionally: 433 | # 434 | # - `mods` (see key bindings) 435 | #mouse_bindings: 436 | # - { mouse: Middle, action: PasteSelection } 437 | 438 | # Key bindings 439 | # 440 | # Key bindings are specified as a list of objects. For example, this is the 441 | # default paste binding: 442 | # 443 | # `- { key: V, mods: Control|Shift, action: Paste }` 444 | # 445 | # Each key binding will specify a: 446 | # 447 | # - `key`: Identifier of the key pressed 448 | # 449 | # - A-Z 450 | # - F1-F24 451 | # - Key0-Key9 452 | # 453 | # A full list with available key codes can be found here: 454 | # https://docs.rs/glutin/*/glutin/event/enum.VirtualKeyCode.html#variants 455 | # 456 | # Instead of using the name of the keys, the `key` field also supports using 457 | # the scancode of the desired key. Scancodes have to be specified as a 458 | # decimal number. This command will allow you to display the hex scancodes 459 | # for certain keys: 460 | # 461 | # `showkey --scancodes`. 462 | # 463 | # Then exactly one of: 464 | # 465 | # - `chars`: Send a byte sequence to the running application 466 | # 467 | # The `chars` field writes the specified string to the terminal. This makes 468 | # it possible to pass escape sequences. To find escape codes for bindings 469 | # like `PageUp` (`"\x1b[5~"`), you can run the command `showkey -a` outside 470 | # of tmux. Note that applications use terminfo to map escape sequences back 471 | # to keys. It is therefore required to update the terminfo when changing an 472 | # escape sequence. 473 | # 474 | # - `action`: Execute a predefined action 475 | # 476 | # - ToggleViMode 477 | # - SearchForward 478 | # - SearchBackward 479 | # - Copy 480 | # - Paste 481 | # - PasteSelection 482 | # - IncreaseFontSize 483 | # - DecreaseFontSize 484 | # - ResetFontSize 485 | # - ScrollPageUp 486 | # - ScrollPageDown 487 | # - ScrollHalfPageUp 488 | # - ScrollHalfPageDown 489 | # - ScrollLineUp 490 | # - ScrollLineDown 491 | # - ScrollToTop 492 | # - ScrollToBottom 493 | # - ClearHistory 494 | # - Hide 495 | # - Minimize 496 | # - Quit 497 | # - ToggleFullscreen 498 | # - SpawnNewInstance 499 | # - ClearLogNotice 500 | # - ClearSelection 501 | # - ReceiveChar 502 | # - None 503 | # 504 | # (`mode: Vi` only): 505 | # - Open 506 | # - Up 507 | # - Down 508 | # - Left 509 | # - Right 510 | # - First 511 | # - Last 512 | # - FirstOccupied 513 | # - High 514 | # - Middle 515 | # - Low 516 | # - SemanticLeft 517 | # - SemanticRight 518 | # - SemanticLeftEnd 519 | # - SemanticRightEnd 520 | # - WordRight 521 | # - WordLeft 522 | # - WordRightEnd 523 | # - WordLeftEnd 524 | # - Bracket 525 | # - ToggleNormalSelection 526 | # - ToggleLineSelection 527 | # - ToggleBlockSelection 528 | # - ToggleSemanticSelection 529 | # - SearchNext 530 | # - SearchPrevious 531 | # - SearchStart 532 | # - SearchEnd 533 | # 534 | # (macOS only): 535 | # - ToggleSimpleFullscreen: Enters fullscreen without occupying another space 536 | # 537 | # (Linux/BSD only): 538 | # - CopySelection: Copies into selection buffer 539 | # 540 | # - `command`: Fork and execute a specified command plus arguments 541 | # 542 | # The `command` field must be a map containing a `program` string and an 543 | # `args` array of command line parameter strings. For example: 544 | # `{ program: "alacritty", args: ["-e", "vttest"] }` 545 | # 546 | # And optionally: 547 | # 548 | # - `mods`: Key modifiers to filter binding actions 549 | # 550 | # - Command 551 | # - Control 552 | # - Option 553 | # - Super 554 | # - Shift 555 | # - Alt 556 | # 557 | # Multiple `mods` can be combined using `|` like this: 558 | # `mods: Control|Shift`. 559 | # Whitespace and capitalization are relevant and must match the example. 560 | # 561 | # - `mode`: Indicate a binding for only specific terminal reported modes 562 | # 563 | # This is mainly used to send applications the correct escape sequences 564 | # when in different modes. 565 | # 566 | # - AppCursor 567 | # - AppKeypad 568 | # - Alt 569 | # 570 | # A `~` operator can be used before a mode to apply the binding whenever 571 | # the mode is *not* active, e.g. `~Alt`. 572 | # 573 | # Bindings are always filled by default, but will be replaced when a new 574 | # binding with the same triggers is defined. To unset a default binding, it can 575 | # be mapped to the `ReceiveChar` action. Alternatively, you can use `None` for 576 | # a no-op if you do not wish to receive input characters for that binding. 577 | # 578 | # If the same trigger is assigned to multiple actions, all of them are executed 579 | # in the order they were defined in. 580 | #key_bindings: 581 | #- { key: Paste, action: Paste } 582 | #- { key: Copy, action: Copy } 583 | #- { key: L, mods: Control, action: ClearLogNotice } 584 | #- { key: L, mods: Control, mode: ~Vi, chars: "\x0c" } 585 | #- { key: PageUp, mods: Shift, mode: ~Alt, action: ScrollPageUp, } 586 | #- { key: PageDown, mods: Shift, mode: ~Alt, action: ScrollPageDown } 587 | #- { key: Home, mods: Shift, mode: ~Alt, action: ScrollToTop, } 588 | #- { key: End, mods: Shift, mode: ~Alt, action: ScrollToBottom } 589 | 590 | # Vi Mode 591 | #- { key: Space, mods: Shift|Control, mode: Vi, action: ScrollToBottom } 592 | #- { key: Space, mods: Shift|Control, action: ToggleViMode } 593 | #- { key: Escape, mode: Vi, action: ClearSelection } 594 | #- { key: I, mode: Vi, action: ScrollToBottom } 595 | #- { key: I, mode: Vi, action: ToggleViMode } 596 | #- { key: Y, mods: Control, mode: Vi, action: ScrollLineUp } 597 | #- { key: E, mods: Control, mode: Vi, action: ScrollLineDown } 598 | #- { key: G, mode: Vi, action: ScrollToTop } 599 | #- { key: G, mods: Shift, mode: Vi, action: ScrollToBottom } 600 | #- { key: B, mods: Control, mode: Vi, action: ScrollPageUp } 601 | #- { key: F, mods: Control, mode: Vi, action: ScrollPageDown } 602 | #- { key: U, mods: Control, mode: Vi, action: ScrollHalfPageUp } 603 | #- { key: D, mods: Control, mode: Vi, action: ScrollHalfPageDown } 604 | #- { key: Y, mode: Vi, action: Copy } 605 | #- { key: Y, mode: Vi, action: ClearSelection } 606 | #- { key: Copy, mode: Vi, action: ClearSelection } 607 | #- { key: V, mode: Vi, action: ToggleNormalSelection } 608 | #- { key: V, mods: Shift, mode: Vi, action: ToggleLineSelection } 609 | #- { key: V, mods: Control, mode: Vi, action: ToggleBlockSelection } 610 | #- { key: V, mods: Alt, mode: Vi, action: ToggleSemanticSelection } 611 | #- { key: Return, mode: Vi, action: Open } 612 | #- { key: K, mode: Vi, action: Up } 613 | #- { key: J, mode: Vi, action: Down } 614 | #- { key: H, mode: Vi, action: Left } 615 | #- { key: L, mode: Vi, action: Right } 616 | #- { key: Up, mode: Vi, action: Up } 617 | #- { key: Down, mode: Vi, action: Down } 618 | #- { key: Left, mode: Vi, action: Left } 619 | #- { key: Right, mode: Vi, action: Right } 620 | #- { key: Key0, mode: Vi, action: First } 621 | #- { key: Key4, mods: Shift, mode: Vi, action: Last } 622 | #- { key: Key6, mods: Shift, mode: Vi, action: FirstOccupied } 623 | #- { key: H, mods: Shift, mode: Vi, action: High } 624 | #- { key: M, mods: Shift, mode: Vi, action: Middle } 625 | #- { key: L, mods: Shift, mode: Vi, action: Low } 626 | #- { key: B, mode: Vi, action: SemanticLeft } 627 | #- { key: W, mode: Vi, action: SemanticRight } 628 | #- { key: E, mode: Vi, action: SemanticRightEnd } 629 | #- { key: B, mods: Shift, mode: Vi, action: WordLeft } 630 | #- { key: W, mods: Shift, mode: Vi, action: WordRight } 631 | #- { key: E, mods: Shift, mode: Vi, action: WordRightEnd } 632 | #- { key: Key5, mods: Shift, mode: Vi, action: Bracket } 633 | #- { key: Slash, mode: Vi, action: SearchForward } 634 | #- { key: Slash, mods: Shift, mode: Vi, action: SearchBackward } 635 | #- { key: N, mode: Vi, action: SearchNext } 636 | #- { key: N, mods: Shift, mode: Vi, action: SearchPrevious } 637 | 638 | # (Windows, Linux, and BSD only) 639 | #- { key: V, mods: Control|Shift, action: Paste } 640 | #- { key: C, mods: Control|Shift, action: Copy } 641 | #- { key: F, mods: Control|Shift, action: SearchForward } 642 | #- { key: B, mods: Control|Shift, action: SearchBackward } 643 | #- { key: C, mods: Control|Shift, mode: Vi, action: ClearSelection } 644 | #- { key: Insert, mods: Shift, action: PasteSelection } 645 | #- { key: Key0, mods: Control, action: ResetFontSize } 646 | #- { key: Equals, mods: Control, action: IncreaseFontSize } 647 | #- { key: Add, mods: Control, action: IncreaseFontSize } 648 | #- { key: Subtract, mods: Control, action: DecreaseFontSize } 649 | #- { key: Minus, mods: Control, action: DecreaseFontSize } 650 | 651 | # (Windows only) 652 | #- { key: Return, mods: Alt, action: ToggleFullscreen } 653 | 654 | # (macOS only) 655 | #- { key: K, mods: Command, mode: ~Vi, chars: "\x0c" } 656 | #- { key: Key0, mods: Command, action: ResetFontSize } 657 | #- { key: Equals, mods: Command, action: IncreaseFontSize } 658 | #- { key: Add, mods: Command, action: IncreaseFontSize } 659 | #- { key: Minus, mods: Command, action: DecreaseFontSize } 660 | #- { key: K, mods: Command, action: ClearHistory } 661 | #- { key: V, mods: Command, action: Paste } 662 | #- { key: C, mods: Command, action: Copy } 663 | #- { key: C, mods: Command, mode: Vi, action: ClearSelection } 664 | #- { key: H, mods: Command, action: Hide } 665 | #- { key: M, mods: Command, action: Minimize } 666 | #- { key: Q, mods: Command, action: Quit } 667 | #- { key: W, mods: Command, action: Quit } 668 | #- { key: N, mods: Command, action: SpawnNewInstance } 669 | #- { key: F, mods: Command|Control, action: ToggleFullscreen } 670 | #- { key: F, mods: Command, action: SearchForward } 671 | #- { key: B, mods: Command, action: SearchBackward } 672 | 673 | #debug: 674 | # Display the time it takes to redraw each frame. 675 | #render_timer: false 676 | 677 | # Keep the log file after quitting Alacritty. 678 | #persistent_logging: false 679 | 680 | # Log level 681 | # 682 | # Values for `log_level`: 683 | # - None 684 | # - Error 685 | # - Warn 686 | # - Info 687 | # - Debug 688 | # - Trace 689 | #log_level: Warn 690 | 691 | # Print all received window events. 692 | #print_events: false 693 | -------------------------------------------------------------------------------- /desktop/cwmrc: -------------------------------------------------------------------------------- 1 | borderwidth 5 2 | color inactiveborder "#161616" 3 | color activeborder "#198038" 4 | 5 | fontname "IBM Plex Sans:pixelsize=18:style=Regular" 6 | 7 | command menu "rofi -show drun" 8 | command spotify "flatpak run com.spotify.Client" 9 | command telegram "flatpak run org.telegram.desktop" 10 | 11 | sticky yes 12 | snapdist 5 13 | gap 5 5 5 5 14 | 15 | bind-key M-Print "screenshot" 16 | bind-key M-Return "xterm" 17 | bind-key MS-Return "9term rc -l" 18 | bind-key MS-r restart 19 | bind-key M-d "rofi -show drun" 20 | bind-key M-l lock 21 | bind-key M-q window-close 22 | 23 | bind-key M-KP_Right group-cycle 24 | bind-key M-KP_Left rgroup-rcycle 25 | bind-key M-KP_Up window-raise 26 | bind-key M-KP_Down window-lower 27 | 28 | bind-key M-1 group-only-1 29 | bind-key M-2 group-only-2 30 | bind-key M-3 group-only-3 31 | bind-key M-4 group-only-4 32 | bind-key M-5 group-only-5 33 | bind-key M-6 group-only-6 34 | bind-key M-7 group-only-7 35 | bind-key M-8 group-only-8 36 | bind-key M-9 group-only-9 37 | bind-key M-0 group-toggle-all 38 | 39 | bind-key MS-1 window-movetogroup-1 40 | bind-key MS-2 window-movetogroup-2 41 | bind-key MS-3 window-movetogroup-3 42 | bind-key MS-4 window-movetogroup-4 43 | bind-key MS-5 window-movetogroup-5 44 | bind-key MS-6 window-movetogroup-6 45 | bind-key MS-7 window-movetogroup-7 46 | bind-key MS-8 window-movetogroup-8 47 | bind-key MS-9 window-movetogroup-9 48 | -------------------------------------------------------------------------------- /desktop/dialogrc: -------------------------------------------------------------------------------- 1 | # 2 | # Run-time configuration file for dialog 3 | # 4 | # Automatically generated by "dialog --create-rc " 5 | # 6 | # 7 | # Types of values: 8 | # 9 | # Number - 10 | # String - "string" 11 | # Boolean - 12 | # Attribute - (foreground,background,highlight?,underline?,reverse?) 13 | 14 | # Set aspect-ration. 15 | aspect = 0 16 | 17 | # Set separator (for multiple widgets output). 18 | separate_widget = "" 19 | 20 | # Set tab-length (for textbox tab-conversion). 21 | tab_len = 0 22 | 23 | # Make tab-traversal for checklist, etc., include the list. 24 | visit_items = OFF 25 | 26 | # Shadow dialog boxes? This also turns on color. 27 | use_shadow = ON 28 | 29 | # Turn color support ON or OFF 30 | use_colors = ON 31 | 32 | # Screen color 33 | screen_color = (BLACK,WHITE,OFF) 34 | 35 | # Shadow color 36 | shadow_color = (WHITE,BLACK,OFF) 37 | 38 | # Dialog box color 39 | dialog_color = (WHITE,GREEN,OFF) 40 | 41 | # Dialog box title color 42 | title_color = (BLACK,GREEN,ON) 43 | 44 | # Dialog box border color 45 | border_color = (WHITE,GREEN,OFF) 46 | 47 | # Active button color 48 | button_active_color = (WHITE,CYAN,ON) 49 | 50 | # Inactive button color 51 | button_inactive_color = dialog_color 52 | 53 | # Active button key color 54 | button_key_active_color = button_active_color 55 | 56 | # Inactive button key color 57 | button_key_inactive_color = (RED,GREEN,OFF) 58 | 59 | # Active button label color 60 | button_label_active_color = button_active_color 61 | 62 | # Inactive button label color 63 | button_label_inactive_color = (BLACK,GREEN,ON) 64 | 65 | # Input box color 66 | inputbox_color = (BLUE,WHITE,OFF) 67 | 68 | # Input box border color 69 | inputbox_border_color = border_color 70 | 71 | # Search box color 72 | searchbox_color = (YELLOW,WHITE,ON) 73 | 74 | # Search box title color 75 | searchbox_title_color = (WHITE,WHITE,ON) 76 | 77 | # Search box border color 78 | searchbox_border_color = (RED,WHITE,OFF) 79 | 80 | # File position indicator color 81 | position_indicator_color = button_key_inactive_color 82 | 83 | # Menu box color 84 | menubox_color = dialog_color 85 | 86 | # Menu box border color 87 | menubox_border_color = border_color 88 | 89 | # Item color 90 | item_color = dialog_color 91 | 92 | # Selected item color 93 | item_selected_color = screen_color 94 | 95 | # Tag color 96 | tag_color = title_color 97 | 98 | # Selected tag color 99 | tag_selected_color = screen_color 100 | 101 | # Tag key color 102 | tag_key_color = button_key_inactive_color 103 | 104 | # Selected tag key color 105 | tag_key_selected_color = (RED,WHITE,ON) 106 | 107 | # Check box color 108 | check_color = dialog_color 109 | 110 | # Selected check box color 111 | check_selected_color = (WHITE,CYAN,ON) 112 | 113 | # Up arrow color 114 | uarrow_color = (GREEN,CYAN,ON) 115 | 116 | # Down arrow color 117 | darrow_color = uarrow_color 118 | 119 | # Item help-text color 120 | itemhelp_color = shadow_color 121 | 122 | # Active form text color 123 | form_active_text_color = inputbox_color 124 | 125 | # Form text color 126 | form_text_color = (CYAN,BLUE,ON) 127 | 128 | # Readonly form item color 129 | form_item_readonly_color = (CYAN,WHITE,ON) 130 | 131 | # Dialog box gauge color 132 | gauge_color = (BLUE,WHITE,ON) 133 | 134 | # Dialog box border2 color 135 | border2_color = dialog_color 136 | 137 | # Input box border2 color 138 | inputbox_border2_color = dialog_color 139 | 140 | # Search box border2 color 141 | searchbox_border2_color = dialog_color 142 | 143 | # Menu box border2 color 144 | menubox_border2_color = dialog_color 145 | -------------------------------------------------------------------------------- /desktop/display_handler: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | if [ "${SRANDRD_EVENT}" != "connected" ]; then 5 | echo Nothing to do when ${SRANDRD_EVENT} 6 | exit 7 | fi 8 | 9 | # 1.5 scale increase is arbitrary, there should be 10 | # a better way 11 | # 12 | calc_scale() { 13 | bc <<< "scale=5;(2-(${ext[0]}/${int[0]}))*1.5" 14 | bc <<< "scale=5;(2-(${ext[2]}/${int[2]}))*1.5" 15 | } 16 | 17 | # panning does not support decimals 18 | calc_panning() { 19 | bc <<< "scale=0;${ext[0]}*${scale[0]}" | cut -f1 -d"." 20 | bc <<< "scale=0;${ext[2]}*${scale[1]}" | cut -f1 -d"." 21 | echo ${int[0]} 22 | echo 0 23 | } 24 | 25 | event="${SRANDRD_OUTPUT} ${SRANDRD_EVENT}" 26 | 27 | mon=$(xrandr --listmonitors | grep ${SRANDRD_OUTPUT}) 28 | 29 | # x_res x_dim y_res y_dim x_pad y_pad 30 | int=(2880 330 1800 210 0 0) 31 | ext=($(echo $mon | cut -f3 -d" " | tr '/x+' ' ' | tr ' ' '\n' )) 32 | scale=($(calc_scale)) 33 | 34 | echo Detected settings: 35 | echo " int ${int[@]}" 36 | echo " ext ${ext[@]}" 37 | echo " scale ${scale[@]}" 38 | 39 | if [ ${ext[0]} -gt ${int[0]} -o ${ext[2]} -gt ${int[2]} ];then 40 | echo External display has more resolution than the internal HiDPI display 41 | echo the default scale should work. If not, patch this tool 42 | exit 43 | fi 44 | 45 | if [ ${ext[1]} -gt ${int[1]} -o ${ext[3]} -gt ${int[3]} ];then 46 | echo External display is smaller than the internal HiDPI display 47 | echo the default scale should work. If not, patch this tool. 48 | exit 49 | fi 50 | 51 | if [ $(bc -l <<< "${scale[0]} < 1") -ne 0 ]; then 52 | echo Display in ${SRANDRD_OUTPUT} has more resolution than internal display Try reseting it with xrandr: 53 | echo 54 | mode=$(xrandr | grep -A 2 "HDMI3" | fgrep '*' | awk '{print $1}') 55 | echo xrandr --output ${SRANDRD_OUTPUT} --scale 1x1 --panning 0x0+0+0 --mode $mode --right-of eDP1 56 | exit 57 | fi 58 | 59 | pan=($(calc_panning int[@] ext[@] scale[@])) 60 | echo "panning ${pan[@]}" 61 | 62 | ratio() { 63 | echo xrandr --output ${SRANDRD_OUTPUT} --panning ${pan[0]}x${pan[1]}+${pan[2]}+${pan[3]} --scale ${scale[0]}x${scale[1]} --right-of eDP1 64 | } 65 | 66 | 67 | case "$event" in 68 | "DP1 connected") ratio;; 69 | "DP2 connected") ratio;; 70 | "HDMI1 connected") ratio;; 71 | "HDMI2 connected") ratio;; 72 | "HDMI3 connected") ratio;; 73 | esac 74 | 75 | -------------------------------------------------------------------------------- /desktop/foot.init: -------------------------------------------------------------------------------- 1 | font = Go Regular:size=12 2 | -------------------------------------------------------------------------------- /desktop/gitconfig: -------------------------------------------------------------------------------- 1 | [gui] 2 | fontui = -family \"DejaVu Sans\" -size 10 -weight normal -slant roman -underline 0 -overstrike 0 3 | fontdiff = -family \"DejaVu Sans Mono\" -size 10 -weight normal -slant roman -underline 0 -overstrike 0 4 | 5 | [pager] 6 | diff = false 7 | 8 | [core] 9 | pager = 9 p 10 | excludesfile = /Users/gdiazlo/.gitignore_global 11 | 12 | [color] 13 | ui = false 14 | branch = false 15 | diff = false 16 | interactive = false 17 | status = false 18 | log = false 19 | 20 | [log] 21 | abbrevCommit = true 22 | 23 | [alias] 24 | tree = log --all --graph --decorate=short --format=format:'%h %d\n [%cr] %an: %s' 25 | 26 | [format] 27 | pretty = "%h - %an, %ar : %s" 28 | 29 | [user] 30 | name = Gabriel Díaz 31 | email = gdiaz@qswarm.com 32 | signingkey = 0413D4D41C7F7267D5F7BF9EE2F33E24C7042D30 33 | 34 | [credential "https://github.com"] 35 | helper = !gh auth git-credential 36 | 37 | [commit] 38 | gpgsign = true 39 | template = /Users/gdiazlo/.stCommitMsg 40 | 41 | [gpg] 42 | program = gpg 43 | 44 | [sendemail] 45 | smtpserver = mail.migadu.com 46 | smtpuser = gdiaz@qswarm.com 47 | smtpencryption = ssl 48 | smtpserverport = 465 49 | -------------------------------------------------------------------------------- /desktop/plan9.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export PLAN9=/usr/local/plan9 4 | export PATH=$PATH:$PLAN9/bin 5 | 6 | -------------------------------------------------------------------------------- /desktop/rio.rasi: -------------------------------------------------------------------------------- 1 | /** 2 | * User: Rasi 3 | * Copyright: Rasmus Steinke 4 | */ 5 | 6 | /* global settings and color variables */ 7 | * { 8 | blue: #0f62fe; 9 | blue-trans: #a6c8ff; 10 | darkblue: #002d9c; 11 | white: #f4f4f4; 12 | green: #198038; 13 | dark-green: #044317; 14 | black: #161616; 15 | grey: #8d8d8d; 16 | medium-grey: #D0D0D0; 17 | dark-grey: #002B36; 18 | urgent: #D75F00; 19 | active: #005F87; 20 | transparent: #000000aa; 21 | spacing: 0em; 22 | font: "DejaVu Sans 14"; 23 | padding: 0px; 24 | background-color: @white; 25 | line-style: "none"; 26 | } 27 | 28 | prompt-box { 29 | background-color: @green; 30 | } 31 | 32 | prompt { 33 | background-color: @green; 34 | text-color: @white; 35 | } 36 | 37 | window { 38 | background-color: @green; 39 | color: @white; 40 | } 41 | mainbox { 42 | padding: 0px; 43 | background-color: @green; 44 | color: @white; 45 | spacing: 0%; 46 | } 47 | 48 | listview { 49 | // Looks. 50 | border-radius: 10px; 51 | border: 5px 5px 5px 5px; 52 | padding: 20px 20px 20px 20px; 53 | margin: 20px 5px 5px 5px; 54 | background-color: @green; 55 | // Enable scrollbar 56 | scrollbar: false; 57 | scrollbar-width: 5px; 58 | fixed-height: true; 59 | reverse: false; 60 | color: @white; 61 | spacing: 0.3em; 62 | } 63 | scrollbar { 64 | color: @white; 65 | background-color: @green; 66 | padding: 1px; 67 | } 68 | element { 69 | border: 0px; 70 | padding: 0px; 71 | margin: 0px; 72 | color: @white; 73 | background-color: @green; 74 | } 75 | element normal.normal { 76 | color: @white; 77 | background-color: @green; 78 | } 79 | element normal.urgent { 80 | color: @urgent; 81 | background-color: @white; 82 | } 83 | element normal.active { 84 | color: @active; 85 | background-color: @white; 86 | } 87 | element selected.normal { 88 | border-radius: 0px; 89 | color: @white; 90 | background-color: @dark-green; 91 | } 92 | element selected.urgent { 93 | color: @white; 94 | background-color: @urgent; 95 | } 96 | element selected.active { 97 | color: @white; 98 | background-color: @active; 99 | } 100 | element alternate.normal { 101 | color: @white; 102 | background-color: @green; 103 | } 104 | element alternate.urgent { 105 | color: @urgent; 106 | background-color: @medium-grey; 107 | } 108 | element alternate.active { 109 | color: @active; 110 | background-color: @medium-grey; 111 | } 112 | inputbar { 113 | spacing: 10; 114 | background-color: @black; 115 | border: 0px 0px 2px 0px; 116 | border-radius: 0px; 117 | padding: 5px 10px 5px 35px; 118 | color: @dark-green; 119 | end: false; 120 | } 121 | 122 | separator { 123 | background-color: @blue; 124 | color: @black; 125 | } 126 | prompt normal.normal { 127 | background-color: @black; 128 | color: @white; 129 | padding: 0px; 130 | } 131 | entry normal.normal { 132 | background-color: @black; 133 | color: @white; 134 | padding: 0px; 135 | } 136 | case-indicator normal.normal { 137 | background-color: @black; 138 | color: @white; 139 | padding: 0px; 140 | } 141 | 142 | message { 143 | margin: 30px 30px 30px 30px; 144 | padding: 20px 30px 20px 20px; 145 | padding: 1px ; 146 | border-radius: 10px; 147 | border: 5px 5px 5px 5px; 148 | } 149 | 150 | prompt-colon { 151 | spacing: 0; 152 | enabled: false; 153 | } 154 | 155 | 156 | -------------------------------------------------------------------------------- /desktop/starship.toml: -------------------------------------------------------------------------------- 1 | 2 | add_newline = false 3 | 4 | [line_break] 5 | disabled = false 6 | 7 | [aws] 8 | style = "" 9 | symbol = "☁ " 10 | 11 | [azure] 12 | symbol = "☁ " 13 | style = " " 14 | 15 | [battery] 16 | full_symbol = "⊙ " 17 | charging_symbol = "⊕ " 18 | discharging_symbol = "⊖ " 19 | 20 | [[battery.display]] 21 | threshold = 10 22 | style = "" 23 | 24 | [buf] 25 | symbol = "buf " 26 | style = "" 27 | 28 | [c] 29 | style = "" 30 | 31 | [character] 32 | success_symbol = "➜ " 33 | error_symbol = "✗ " 34 | 35 | [cmake] 36 | style = "" 37 | 38 | [cobol] 39 | style = "" 40 | 41 | [cmd_duration] 42 | style = "" 43 | 44 | [conda] 45 | style = "" 46 | symbol = "𝕔" 47 | 48 | [container] 49 | style = "" 50 | 51 | [crystal] 52 | style = "" 53 | symbol = "⌬ " 54 | 55 | [daml] 56 | style = "" 57 | 58 | [dart] 59 | style = "" 60 | symbol = "𝕕 " 61 | 62 | [deno] 63 | style = "" 64 | symbol = "deno " 65 | 66 | 67 | [directory] 68 | style = "" 69 | read_only = "🔒" 70 | read_only_style = "" 71 | home_symbol = "~" 72 | truncation_length = 3 73 | 74 | [docker_context] 75 | style = "" 76 | symbol = "❃ " 77 | 78 | [dotnet] 79 | symbol = "🥅 " 80 | style = "" 81 | 82 | [elixir] 83 | symbol = "🔮 " 84 | style = "" 85 | 86 | [elm] 87 | symbol = "🌳 " 88 | style = "" 89 | 90 | [env_var] 91 | style = "" 92 | 93 | [erlang] 94 | symbol = " " 95 | style = "" 96 | 97 | [fill] 98 | symbol = "-" 99 | style = "" 100 | 101 | [gcloud] 102 | symbol = "☁ " 103 | style = "" 104 | 105 | [git_branch] 106 | style = "" 107 | symbol = "⌥ " 108 | 109 | [git_commit] 110 | style = "" 111 | commit_hash_length = 4 112 | tag_symbol = "⌂ " 113 | 114 | [git_state] 115 | style = "" 116 | cherry_pick = "[⎇ PICKING]" 117 | 118 | [git_metrics] 119 | added_style = "" 120 | deleted_style = "" 121 | 122 | [git_status] 123 | style = "" 124 | conflicted = "🏳" 125 | ahead = "🏎💨" 126 | behind = "😰" 127 | diverged = "😵" 128 | up_to_date = "✓" 129 | untracked = "🤷" 130 | stashed = "📦" 131 | modified = "📝" 132 | staged = '++\($count\)' 133 | renamed = "👅" 134 | deleted = "🗑" 135 | 136 | [golang] 137 | style = "" 138 | format = "via Go $version " 139 | 140 | [haskell] 141 | symbol = "λ " 142 | style = "" 143 | 144 | [helm] 145 | symbol = "⎈ " 146 | style = "" 147 | 148 | [hostname] 149 | ssh_symbol = "☏ " 150 | style = "" 151 | 152 | [java] 153 | style = "" 154 | symbol = "☆ " 155 | 156 | [jobs] 157 | style = "" 158 | symbol = "+ " 159 | number_threshold = 4 160 | symbol_threshold = 0 161 | 162 | [julia] 163 | style = "" 164 | symbol = "ஃ " 165 | 166 | [kotlin] 167 | style = "" 168 | symbol = "🅺 " 169 | 170 | [kubernetes] 171 | style = "" 172 | symbol = "☸ " 173 | 174 | [localip] 175 | ssh_only = false 176 | style = "" 177 | disabled = true 178 | 179 | [lua] 180 | symbol = "☾ " 181 | style = "" 182 | 183 | [memory_usage] 184 | symbol = "∃" 185 | style = "" 186 | 187 | [hg_branch] 188 | symbol = "⌥ " 189 | style = "" 190 | 191 | [nim] 192 | symbol = "♛ " 193 | style = "" 194 | 195 | [nix_shell] 196 | symbol = "❄ " 197 | style = "" 198 | 199 | [nodejs] 200 | symbol = "♻ " 201 | style = "" 202 | 203 | [ocaml] 204 | symbol = "⋌ " 205 | style = "" 206 | 207 | [openstack] 208 | style = "" 209 | symbol = "☁ " 210 | 211 | [package] 212 | style = "" 213 | symbol = "❏ " 214 | 215 | [perl] 216 | style = "" 217 | symbol = "perl " 218 | 219 | [php] 220 | style = "" 221 | symbol = "php " 222 | 223 | [pulumi] 224 | style = "" 225 | symbol = "pulumi " 226 | 227 | [purescript] 228 | style = "" 229 | symbol = "<=> " 230 | 231 | [python] 232 | style = "" 233 | symbol = "python " 234 | 235 | [rlang] 236 | style = "" 237 | symbol = "R " 238 | 239 | [red] 240 | style = "" 241 | symbol = "red " 242 | 243 | [ruby] 244 | style = "" 245 | symbol = "♢ " 246 | 247 | [rust] 248 | style = "" 249 | symbol = "rust " 250 | 251 | [scala] 252 | style = "" 253 | symbol = "scala " 254 | 255 | [shell] 256 | style = "shell " 257 | 258 | [shlvl] 259 | style = "" 260 | symbol = "shlvl " 261 | 262 | [singularity] 263 | style = "" 264 | 265 | [spack] 266 | style = "" 267 | symbol = "spack " 268 | 269 | [status] 270 | style = "" 271 | symbol = "✖ " 272 | success_symbol = "✔ " 273 | format = '[\[$symbol$common_meaning$signal_name$maybe_int\]]($style) ' 274 | map_symbol = true 275 | disabled = false 276 | 277 | [sudo] 278 | style = "" 279 | symbol = "✚ " 280 | disabled = false 281 | 282 | [swift] 283 | style = "" 284 | symbol = "swift " 285 | 286 | [terraform] 287 | style = "" 288 | symbol = "🌑 " 289 | 290 | [time] 291 | style = "" 292 | disabled = true 293 | format = '[\[ $time \]]($style) ' 294 | time_format = "%T" 295 | 296 | [username] 297 | style_user = "" 298 | style_root = "" 299 | format = "$user " 300 | disabled = true 301 | show_always = true 302 | 303 | [vagrant] 304 | style = "" 305 | symbol = "⍱ " 306 | 307 | [vlang] 308 | style = "" 309 | symbol = "V " 310 | 311 | [vcsh] 312 | style = "" 313 | symbol = "" 314 | 315 | [zig] 316 | style = "" 317 | symbol = "⚡ " 318 | 319 | -------------------------------------------------------------------------------- /desktop/swaywm_config: -------------------------------------------------------------------------------- 1 | # Default config for sway 2 | # 3 | # Copy this to ~/.config/sway/config and edit it to your liking. 4 | # 5 | # Read `man 5 sway` for a complete reference. 6 | 7 | ### Variables 8 | # 9 | # Logo key. Use Mod1 for Alt. 10 | set $mod Mod1 11 | # Home row direction keys, like vim 12 | set $left h 13 | set $down j 14 | set $up k 15 | set $right l 16 | # Your preferred terminal emulator 17 | set $term alacritty 18 | # Your preferred application launcher 19 | # Note: it's recommended that you pass the final command to sway 20 | set $menu dmenu_path | j4-dmenu-desktop | xargs swaymsg exec -- 21 | 22 | font pango: Copper Hewitt Medium 12 23 | 24 | ### Output configuration 25 | # 26 | # Default wallpaper (more resolutions are available in /usr/local/share/backgrounds/sway/) 27 | output * bg /usr/local/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill 28 | output eDP-1 scale 2 29 | # 30 | # Example configuration: 31 | # 32 | # output HDMI-A-1 resolution 1920x1080 position 1920,0 33 | # 34 | # You can get the names of your outputs by running: swaymsg -t get_outputs 35 | 36 | set $laptop eDP-1 37 | bindswitch lid:on output $laptop disable 38 | bindswitch lid:off output $laptop enable 39 | 40 | ### Idle configuration 41 | # 42 | # Example configuration: 43 | # 44 | exec swayidle -w \ 45 | timeout 300 'swaylock -f -c 000000' \ 46 | timeout 600 'swaymsg "output * dpms off"' \ 47 | resume 'swaymsg "output * dpms on"' 48 | # before-sleep 'swaylock -f -c 000000' 49 | # 50 | # This will lock your screen after 300 seconds of inactivity, then turn off 51 | # your displays after another 300 seconds, and turn your screens back on when 52 | # resumed. It will also lock your screen before your computer goes to sleep. 53 | 54 | ### Input configuration 55 | # 56 | # Example configuration: 57 | # 58 | # input "2:14:SynPS/2_Synaptics_TouchPad" { 59 | # dwt enabled 60 | # tap enabled 61 | # natural_scroll enabled 62 | # middle_emulation enabled 63 | # } 64 | # 65 | # You can get the names of your inputs by running: swaymsg -t get_inputs 66 | # Read `man 5 sway-input` for more information about this section. 67 | 68 | input type:keyboard { 69 | xkb_layout "es" 70 | } 71 | 72 | ### Key bindings 73 | # 74 | # Basics: 75 | # 76 | # Start a terminal 77 | bindsym $mod+Return exec $term 78 | 79 | # Kill focused window 80 | bindsym $mod+Shift+q kill 81 | 82 | # Start your launcher 83 | bindsym $mod+d exec $menu 84 | 85 | # Drag floating windows by holding down $mod and left mouse button. 86 | # Resize them with right mouse button + $mod. 87 | # Despite the name, also works for non-floating windows. 88 | # Change normal to inverse to use left mouse button for resizing and right 89 | # mouse button for dragging. 90 | floating_modifier $mod normal 91 | 92 | # Reload the configuration file 93 | bindsym $mod+Shift+c reload 94 | 95 | # Lock screen 96 | bindsym $mod+Shift+p exec swaylock -f -c 000000 97 | # Exit sway (logs you out of your Wayland session) 98 | bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit' 99 | # 100 | # Moving around: 101 | # 102 | # Move your focus around 103 | bindsym $mod+$left focus left 104 | bindsym $mod+$down focus down 105 | bindsym $mod+$up focus up 106 | bindsym $mod+$right focus right 107 | # Or use $mod+[up|down|left|right] 108 | bindsym $mod+Left focus left 109 | bindsym $mod+Down focus down 110 | bindsym $mod+Up focus up 111 | bindsym $mod+Right focus right 112 | 113 | # Move the focused window with the same, but add Shift 114 | bindsym $mod+Shift+$left move left 115 | bindsym $mod+Shift+$down move down 116 | bindsym $mod+Shift+$up move up 117 | bindsym $mod+Shift+$right move right 118 | # Ditto, with arrow keys 119 | bindsym $mod+Shift+Left move left 120 | bindsym $mod+Shift+Down move down 121 | bindsym $mod+Shift+Up move up 122 | bindsym $mod+Shift+Right move right 123 | # 124 | # Workspaces: 125 | # 126 | # Switch to workspace 127 | bindsym $mod+1 workspace 1 128 | bindsym $mod+2 workspace 2 129 | bindsym $mod+3 workspace 3 130 | bindsym $mod+4 workspace 4 131 | bindsym $mod+5 workspace 5 132 | bindsym $mod+6 workspace 6 133 | bindsym $mod+7 workspace 7 134 | bindsym $mod+8 workspace 8 135 | bindsym $mod+9 workspace 9 136 | bindsym $mod+0 workspace 10 137 | # Move focused container to workspace 138 | bindsym $mod+Shift+1 move container to workspace 1 139 | bindsym $mod+Shift+2 move container to workspace 2 140 | bindsym $mod+Shift+3 move container to workspace 3 141 | bindsym $mod+Shift+4 move container to workspace 4 142 | bindsym $mod+Shift+5 move container to workspace 5 143 | bindsym $mod+Shift+6 move container to workspace 6 144 | bindsym $mod+Shift+7 move container to workspace 7 145 | bindsym $mod+Shift+8 move container to workspace 8 146 | bindsym $mod+Shift+9 move container to workspace 9 147 | bindsym $mod+Shift+0 move container to workspace 10 148 | # Note: workspaces can have any name you want, not just numbers. 149 | # We just use 1-10 as the default. 150 | # 151 | # Layout stuff: 152 | # 153 | # You can "split" the current object of your focus with 154 | # $mod+b or $mod+v, for horizontal and vertical splits 155 | # respectively. 156 | bindsym $mod+b splith 157 | bindsym $mod+v splitv 158 | 159 | # Switch the current container between different layout styles 160 | bindsym $mod+s layout stacking 161 | bindsym $mod+w layout tabbed 162 | bindsym $mod+e layout toggle split 163 | 164 | # Make the current focus fullscreen 165 | bindsym $mod+f fullscreen 166 | 167 | # Toggle the current focus between tiling and floating mode 168 | bindsym $mod+Shift+space floating toggle 169 | 170 | # Swap focus between the tiling area and the floating area 171 | bindsym $mod+space focus mode_toggle 172 | 173 | # Move focus to the parent container 174 | bindsym $mod+a focus parent 175 | # 176 | # Scratchpad: 177 | # 178 | # Sway has a "scratchpad", which is a bag of holding for windows. 179 | # You can send windows there and get them back later. 180 | 181 | # Move the currently focused window to the scratchpad 182 | bindsym $mod+Shift+minus move scratchpad 183 | 184 | # Show the next scratchpad window or hide the focused scratchpad window. 185 | # If there are multiple scratchpad windows, this command cycles through them. 186 | bindsym $mod+minus scratchpad show 187 | # 188 | # Resizing containers: 189 | # 190 | mode "resize" { 191 | # left will shrink the containers width 192 | # right will grow the containers width 193 | # up will shrink the containers height 194 | # down will grow the containers height 195 | bindsym $left resize shrink width 10px 196 | bindsym $down resize grow height 10px 197 | bindsym $up resize shrink height 10px 198 | bindsym $right resize grow width 10px 199 | 200 | # Ditto, with arrow keys 201 | bindsym Left resize shrink width 10px 202 | bindsym Down resize grow height 10px 203 | bindsym Up resize shrink height 10px 204 | bindsym Right resize grow width 10px 205 | 206 | # Return to default mode 207 | bindsym Return mode "default" 208 | bindsym Escape mode "default" 209 | } 210 | bindsym $mod+r mode "resize" 211 | 212 | # 213 | # Status Bar: 214 | # 215 | # Read `man 5 sway-bar` for more information about this section. 216 | bar { 217 | position top 218 | #font pango:Terminus (TTF) 10 219 | 220 | # When the status_command prints a new line to stdout, swaybar updates. 221 | # The default just shows the current date and time. 222 | status_command i3status 223 | # status_command while date +'%Y-%m-%d %l:%M:%S %p'; do sleep 1; done 224 | 225 | colors { 226 | statusline #ffffff 227 | background #323232 228 | inactive_workspace #32323200 #32323200 #5c5c5c 229 | } 230 | 231 | } 232 | 233 | 234 | include /usr/local/etc/sway/config.d/* 235 | -------------------------------------------------------------------------------- /desktop/vimrc: -------------------------------------------------------------------------------- 1 | set backupdir=/tmp//,. 2 | set directory=/tmp//,. 3 | -------------------------------------------------------------------------------- /desktop/wezterm.lua: -------------------------------------------------------------------------------- 1 | local wezterm = require 'wezterm'; 2 | return { 3 | font = wezterm.font("Iosevka"), 4 | font_size = 13, 5 | color_scheme = "AtomOneLight", 6 | use_ime = true, 7 | window_frame = { 8 | 9 | font = wezterm.font({family="IBM Plex Sans", weight="Bold"}), 10 | font_size = 13.0, 11 | active_titlebar_bg = "#f4f4f4", 12 | inactive_titlebar_bg = "#333333", 13 | }, 14 | launch_menu = { 15 | { 16 | label = "Plan9", 17 | args = {"/usr/local/plan9/bin/rc","-l"}, 18 | }, 19 | }, 20 | enable_wayland = true, 21 | } 22 | -------------------------------------------------------------------------------- /desktop/xbindkeysrc: -------------------------------------------------------------------------------- 1 | "xbindkeys_show" 2 | Alt + k 3 | 4 | # Increase volume 5 | "pactl set-sink-volume @DEFAULT_SINK@ +1000" 6 | XF86AudioRaiseVolume 7 | 8 | # Decrease volume 9 | "pactl set-sink-volume @DEFAULT_SINK@ -1000" 10 | XF86AudioLowerVolume 11 | 12 | # Mute volume 13 | "pactl set-sink-mute @DEFAULT_SINK@ toggle" 14 | XF86AudioMute 15 | 16 | # Increase backlight 17 | "xbacklight -inc 10" 18 | XF86MonBrightnessUp 19 | 20 | # Decrease backlight 21 | "xbacklight -dec 10" 22 | XF86MonBrightnessDown 23 | 24 | "L comp -e | 9p write acme/`{dial unix!`{namespace}/acmefocused}/errors" 25 | Alt + c 26 | 27 | "L refs | 9p write acme/`{dial unix!`{namespace}/acmefocused}/errors" 28 | Alt + r 29 | 30 | "L def | 9p write acme/`{dial unix!`{namespace}/acmefocused}/errors" 31 | Alt + d 32 | 33 | "L sig" 34 | Alt + i 35 | 36 | "rofi -show drun" 37 | Alt + m 38 | 39 | "9 9term" 40 | Alt + Return 41 | 42 | "xterm bash -l" 43 | Shift+Alt + Return 44 | -------------------------------------------------------------------------------- /desktop/xmodmap: -------------------------------------------------------------------------------- 1 | ! multimedia keys for macbook pro 2 | !keycode 232 = XF86MonBrightnessDown 3 | !keycode 233 = XF86MonBrightnessUp 4 | 5 | !keycode 121 = XF86AudioMute 6 | !keycode 122 = XF86AudioRaiseVolume 7 | !keycode 123 = XF86AudioLowerVolume 8 | 9 | !keycode 173 = XF86AudioPrev 10 | !keycode 172 = XF86AudioPlay 11 | !keycode 171 = XF86AudioNext 12 | 13 | ! Right Control key as META 14 | ! on IBM PS2 model M keyboard 15 | 16 | remove control = Control_R 17 | add mod4 = Control_R 18 | 19 | -------------------------------------------------------------------------------- /doc/p9p-email.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: plan9port email 3 | lang: en-US 4 | --- 5 | 6 | ## plan9port email 7 | 8 | This article describes how to work with email using the 9 | [plan9port] environment. 10 | 11 | Most of the tools included in [plan9port] came, obviously, from [Plan9], 12 | but even if they're old, there have been maintained to keep them working 13 | on current systems. 14 | 15 | The instructions to set up email on Plan9 can be read on the [wiki] 16 | 17 | To read email from [acme], we need to set up: 18 | 19 | - [secstored] to store auth information on disk 20 | - [factotum] as an authentication agent 21 | - [upas/fs] or [mailfs] to present a mailbox with a filesystem interface 22 | - [upas/smtp] or other MTA like [msmtp] to send emails 23 | - [ned] or Mail to manage the emails 24 | - and some other utilities 25 | 26 | ### Install plan9port 27 | 28 | To install plan9port I do: 29 | 30 | ~~~~{.bash} 31 | $ git clone https://github.com/9fans/plan9port.git $HOME/.plan9 32 | $ cd $HOME/.plan9 33 | $ ./INSTALL 34 | ~~~~ 35 | 36 | I do not install plan9port system wide, but you can follow the 37 | standard location and install it in ```/usr/local/plan9``` or where 38 | you want. 39 | 40 | To install [upas] utilities, we need to manually build them: 41 | 42 | ~~~~{.bash} 43 | $ cd $HOME/.plan9/src/cmd/upas 44 | $ $HOME/.plan9/bin/9 mk install 45 | ~~~~ 46 | 47 | ### Environment 48 | 49 | On Plan9, services posted an entry into the srv filesystem so others 50 | could easily mount their filesystem from them and use they services. On 51 | Plan9Port libraries and programs expect a ```$NAMESPACE``` varaible to 52 | point to that location. 53 | 54 | Also, on Plan9 there is the [network database], which in plan9port is 55 | located in ```$PLAN9/ndb```. On the current plan9port implementation, 56 | the ndb is not generally used, and programs expect some hostnames to 57 | work with their default settings. 58 | 59 | On my system, I prepare my environment on my ```$HOME/.profile```[^1] 60 | file like this: 61 | 62 | [^1]: To read my current profile, take a loot at my [dot files](https://github.com/gdiazlo/p9penv) 63 | 64 | 65 | ~~~~{.bash} 66 | # ~/.profile 67 | export PLAN9=$HOME/.plan9 68 | 69 | NAMESPACE=/tmp/$USER/ns/root 70 | if [ -d $XDG_RUNTIME_DIR ]; then 71 | NAMESPACE=$XDG_RUNTIME_DIR/ns/root 72 | fi 73 | export NAMESPACE 74 | mkdir -p $NAMESPACE 75 | 76 | new_p9p_session() { 77 | for proc in fontsrv secstored factotum plumber; do 78 | pgrep $proc 2>&1 > /dev/null 79 | if [ $? -ne 0 ]; then 80 | $PLAN9/bin/9 $proc & 81 | fi 82 | done 83 | } 84 | 85 | new_p9p_session 86 | ~~~~ 87 | 88 | Please read ```[XDG_RUNTIME_DIR]``` documentation, as that folder is deleted when the user logs out. 89 | 90 | Then reload your user profile either by logging out and logging in or by loading your profile on your current session: 91 | 92 | ~~~~{.bash} 93 | $ source $HOME/.profile 94 | ~~~~ 95 | 96 | ### Setting up secstored 97 | 98 | You can skip this section and go directly to the section abut mailfs 99 | below if you do not plan to use secstore to persist your secrets on disk. 100 | 101 | It serves files using the secstore protocol. It allows to securely store 102 | and retrieve files from an encrypted data store on disk. 103 | 104 | Secstored starts when the ```new_p9p_session``` function executes when 105 | your profile is loaded. 106 | 107 | Secstored programs use by default the host called ```secstore``` as its server name, so we add that to our ```/etc/hosts``` file: 108 | 109 | ~~~~{.bash} 110 | # echo 127.0.0.1 secstore >> /etc/hosts 111 | ~~~~ 112 | 113 | To use it, we need to create an user into secstore with the ```secuser``` command: 114 | 115 | ~~~~{.bash} 116 | $ 9 secuser $USER 117 | new account (because $PLAN9/secstore/$USER account does not exist) 118 | $USER password: 119 | retype password: 120 | expires [DDMMYYYY, default = 12052021]: 121 | Enabled or Disabled [default Enabled]: 122 | require STA? [default no]: 123 | comments [default = ]: 124 | hostname Jun 12 22:53:40 CHANGELOGIN for '$USER' 125 | change written 126 | $ 127 | ~~~~ 128 | 129 | Files stored in secstore are saved in ```$PLAN9/secstore/store/$USER/``` 130 | by default, filenames can be read, but the contents are encrypted. 131 | 132 | There are no files yet on our secstore: 133 | 134 | ~~~~{.bash} 135 | $ ls $PLAN9/secstore/store/$USER/ 136 | $ 137 | ~~~~ 138 | 139 | Then we need to store our credentials in file called ```factotum``` 140 | using secstore. 141 | 142 | To start, we need to upload an empty ```factotum``` fie to secstore, 143 | so the script ```ipso``` works correctly. 144 | 145 | ~~~~{.bash} 146 | $ touch factotum 147 | $ secstore -p factotum 148 | $ rm factotum 149 | ~~~~ 150 | 151 | Other rough edges of the script is the way select where to store the 152 | temporary files. I use a modified version which uses $XDG_RUNTIME_DIR 153 | as a base. 154 | 155 | 156 | ~~~~ 157 | #!/usr/local/plan9/bin/rc 158 | 159 | . 9.rc 160 | name = secstore 161 | get = secstoreget 162 | put = secstoreput 163 | edit = no 164 | load = no 165 | flush = no 166 | 167 | fn secstoreget{ 168 | secstore -i -g $1 <_password 169 | } 170 | 171 | fn secstoreput{ 172 | secstore -i -p $1 <_password 173 | } 174 | 175 | fn aesget{ 176 | if(! ~ $1 /*){ 177 | echo >[1=2] ipso: aescbc requires fully qualified pathname 178 | exit usage 179 | } 180 | aescbc -i -d < $1 > `{basename $1} <[3] _password 181 | } 182 | 183 | fn aesput{ 184 | aescbc -i -e > $1 < `{basename $1} <[3] _password 185 | } 186 | 187 | fn editedfiles{ 188 | if(~ $get aesget){ 189 | for(i in $files) 190 | if(ls -tr | sed '1,/^_timestamp$/d' | grep -s '^'^`{basename $i}^'$') 191 | echo $i 192 | } 193 | if not 194 | ls -tr | sed '1,/^_timestamp$/d' 195 | } 196 | 197 | while(~ $1 -*){ 198 | switch($1){ 199 | case -a 200 | name = aescbc 201 | get = aesget 202 | put = aesput 203 | case -f 204 | flush = yes 205 | case -e 206 | edit = yes 207 | case -l 208 | load = yes 209 | case * 210 | echo >[2=1] 'usage: ipso [-a -f -e -l] [-s] [file ...]' 211 | exit usage 212 | } 213 | shift 214 | } 215 | 216 | if(~ $flush no && ~ $edit no && ~ $load no){ 217 | edit = yes 218 | if(~ factotum $*){ 219 | load = yes 220 | flush = yes 221 | } 222 | } 223 | 224 | if(~ $flush yes && ~ $edit no && ~ $load no){ 225 | echo flushing old keys 226 | echo delkey | 9p write factotum/ctl 227 | exit 0 228 | } 229 | 230 | if(~ $get aesget && ~ $#* 0){ 231 | echo >[2=1] ipso: must specify a fully qualified file name for aescbc '(-a)' 232 | exit usage 233 | } 234 | 235 | user=`{whoami} 236 | cd $XDG_RUNTIME_DIR || exit $status 237 | mkdir -p ipso.$user 238 | chmod 700 ipso.$user || exit $status 239 | cd ipso.$user 240 | dir=`{pwd} 241 | dir=$"dir 242 | 243 | fn sigexit { 244 | rm -rf $dir 245 | } 246 | 247 | if ( ~ $edit yes ) echo ' 248 | Warning: The editor will display the secret contents of 249 | your '$name' files in the clear, and they will 250 | be stored temporarily in '^$dir^' 251 | in the clear, along with your password. 252 | ' 253 | 254 | # get password and remember it 255 | readcons -s $name^' password' >_password 256 | 257 | # get list of files 258 | if(~ $#* 0){ 259 | if(! secstore -G . -i < _password > _listing){ 260 | echo 'secstore read failed - bad password?' 261 | sleep 2 262 | exit password 263 | } 264 | files=`{sed 's/[ ]+.*//' _listing} 265 | } 266 | if not 267 | files = $* 268 | 269 | # copy the files to local ramfs 270 | for(i in $files){ 271 | if(! $get $i){ 272 | echo $name ' read failed - bad password?' 273 | sleep 2 274 | exit password 275 | } 276 | } 277 | sleep 2; date > _timestamp # so we can find which files have been edited. 278 | 279 | # edit the files 280 | if(~ $edit yes){ 281 | B `{for(i in $files) basename $i} 282 | readcons 'type enter when finished editing' >/dev/null 283 | } 284 | if(~ $flush yes ){ 285 | echo flushing old keys 286 | echo delkey | 9p write factotum/ctl 287 | } 288 | if(~ $load yes){ 289 | echo loading factotum keys 290 | if (~ factotum $files) cat factotum | 9p write -l factotum/ctl 291 | } 292 | 293 | # copy the files back 294 | for(i in `{editedfiles}){ 295 | prompt='copy '''^`{basename $i}^''' back? [y/n/x]' 296 | switch(`{readcons $prompt}){ 297 | case [yY]* 298 | if(! $put $i){ 299 | echo $name ' read failed - bad password?' 300 | sleep 2 301 | exit password 302 | } 303 | echo ''''$i'''' copied to $name 304 | if(~ $i factotum && ! ~ $load yes){ # do not do it twice 305 | cat $i | 9p write -l factotum/ctl 306 | } 307 | case [xXqQ]* 308 | exit 309 | case [nN]* * 310 | echo ''''$i'''' skipped 311 | } 312 | } 313 | 314 | exit '' 315 | ~~~~ 316 | 317 | To execute ```ipso``` we first need to open a plan9port editor like 318 | [acme]. 319 | 320 | ~~~~{.bash} 321 | $ ipso 322 | 323 | Warning: The editor will display the secret contents of 324 | your secstore files in the clear, and they will 325 | be stored temporarily in /run/user/1000/ipso.gdiazlo 326 | in the clear, along with your password. 327 | 328 | secstore password: 329 | server: your_hostname 330 | server: your_hostname 331 | type enter when finished editing: 332 | ~~~~ 333 | 334 | Then we need to fill the acme window with the contents of our 335 | authentication information: 336 | 337 | ~~~~ 338 | key proto=pass role=client server=imap.mail_provider.com service=imap user=user@mail_provider.com !password=my_imap_password 339 | ~~~~ 340 | 341 | We need to save the file, close it, and press enter on the console where 342 | ipso is waiting. 343 | 344 | When we finish the process, we will have a file in 345 | ```$PLAN9/secstore/store/$USER/``` called ```factotum``` whose contents 346 | we cannot read. 347 | 348 | ### Setting up factotum 349 | 350 | factotum is the authentication agent that will identify us to the remote 351 | servers. When started, if we have configured a secstore hostname properly, 352 | it will try to load keys from a file called factotum stored in the 353 | secstore server. We can also use ```ipso``` to load our keys using the 354 | ```-l``` option. 355 | 356 | ~~~~{.bash} 357 | $ ipso -l 358 | secstore password: 359 | server: your_host_name 360 | server: your_host_name 361 | loading factotum keys 362 | $ 363 | ~~~~ 364 | 365 | After that, we can read the list of entries loaded into ```factotum`` 366 | with the following command: 367 | 368 | ~~~~{.bash} 369 | $ 9 9p read factotum/ctl 370 | key proto=pass role=client server=imap.mail_provider.com service=imap user=user@mail_provider.com !password? 371 | ~~~~ 372 | 373 | We can store credentials for more services in ````factotum``` 374 | 375 | ### Accesing an imap inbox with ```mailfs``` 376 | 377 | If we have followed the secstore and factotum set up, mailfs will not ask 378 | us for a password, but if we don't, mailfs will ask us for a password 379 | and will fill factotum with our log in information. This information 380 | will not be persisted, so the next time we access our imap service, 381 | we are going to need to type our imap password again. 382 | 383 | Now that we can identify ourselves to our imap service, we can instruct 384 | mailfs to connect to our server: 385 | 386 | ~~~~{.bash} 387 | $ 9 mailfs -t -u my_user@mail_provider.com imap.mail_provider.com 388 | $ 9 9p ls mail 389 | Drafts 390 | Junk 391 | Sent 392 | Trash 393 | ctl 394 | mbox 395 | ~~~~ 396 | 397 | This has created a socket in ```$NAMESPACE``` called ```mail``` which 398 | is serving a 9P connection to email clients like acme Mail and [ned]. 399 | 400 | If you want to explore the filesystem interface using regular Linux tool 401 | you can use the 9pfuse tool to mount the ```mail``` socket into a folder 402 | like $HOME/mail: 403 | 404 | ~~~~{.bash} 405 | $ mkdir -p $HOME/mail/personal 406 | $ 9pfuse $NAMESPACE/mail $HOME/mail/personal/ 407 | $ ls mail/personal/mbox/ 408 | 1 2 3 4 6 7 ctl search 409 | $ 410 | ~~~~ 411 | 412 | And here at last, my inbox as presented by [ned]: 413 | 414 | ~~~~{.bash} 415 | $ $PLAN9/bin/upas/nedmail -S personal 416 | 6 messages 417 | : ,h 418 | 1 H 0 6/12 22:12 info@mailer.netflix.com What's playing next, Gabriel? 419 | 2 H 0 6/12 18:46 technews-editor@acm.org ACM TechNews, Friday, June 12, 2020 420 | 3 H 0 6/12 18:02 mensajeria@phidias.es Avisos de comunicados y mensajes 421 | 4 H 0 6/12 17:15 contact@communaute.n-py.com Renovación de tu tarjeta No'Souci 422 | 5 H 0 6/12 13:06 mensajeria@phidias.es Actividad de fin de curso - Infantil 423 | 6 H 0 6/12 11:58 mensajeria@phidias.es Para la semana que viene y un articulito :) 424 | : 425 | ~~~~ 426 | 427 | [ned] is a very neat program to work with email. It is easy to deal with multiple emails, and with attachments. For example: 428 | 429 | - ```: g/9fans/ s 9fans``` will save all emails with the 9fans word in 430 | the headers to the 9fans folder 431 | - ```: g/tuhs/ h``` will list all emails with tuhs in the headers 432 | - ```: 2,7 d``` will delete emails two to seven 433 | - ```: y``` will execute the commands againts the mail box, writting 434 | the changes the commands made 435 | 436 | ### Sending email 437 | 438 | This set up will use a SMTP service from your email provider. For it to 439 | work we need to configure the ```$HOME/mail/pipefrom``` file. 440 | 441 | This script will be in charge to send the email as if it were the 442 | system mailer: 443 | 444 | ~~~~{.bash} 445 | #!/bin/bash 446 | 447 | if [ -z "$upasname" ]; then 448 | upasname="my_user@my_email_domain" 449 | fi 450 | server="tcp!smtp.my_email_provider.com!smtp" 451 | 452 | # the -sa options are for TLS and authentication against $server 453 | cat | $PLAN9/bin/upas/smtp -sa -u $upasname $server $upasname $* 454 | ~~~~ 455 | 456 | Our mailer will use [upas/smtp] to send our email, and it will use 457 | factotum credentials to authenticate against the smtp server of our 458 | provider. We can use other mailers such as [msmtp], but it wont use 459 | factotum to authenticate. Some mailers might be able to integrate with 460 | secstore using scripts to get the secrets from it. 461 | 462 | Also, acme Mail will complete our ```From``` address like our 463 | ```$USER@$HOSTNAME``` or using the ```upasname``` variable, if we want 464 | to change this, which is almost always, we need to create a file in 465 | ```$HOME/mail/headers``` containing the ```From``` line of our emails: 466 | 467 | 468 | ~~~~{.bash} 469 | $ cat headers 470 | From: My Name and Surnames 471 | ~~~~ 472 | 473 | Or we need to export out ```upasname``` variable as you can see on the next section. 474 | 475 | ### Multiple accounts 476 | 477 | Let's say you have, like me, multiple email accounts, one for work and 478 | one for personal stuff for example. 479 | 480 | Reading email is as simple as: 481 | 482 | ~~~~{.bash} 483 | $ 9 mailfs -t -s personal -u my_personal@emailaddr.com imap.personal_provider.com 484 | $ 9 mailfs -t -s work -u my_work@emailaddr.com imap.work_provider.com 485 | ~~~~ 486 | 487 | Now we have two sockets under $NAMESPACE: work and personal. To read 488 | email with [ned][^2] we need to indicate it the name of the mailbox we 489 | want to read: 490 | 491 | [^2]: Please note the ```nedmail``` option ```-S``` is only present in 492 | plan9port, it does not appear in then Plan9 man page, and ```nedmail``` 493 | does not have a man page on plan9port. 494 | 495 | ~~~~{.bash} 496 | $ $PLAN9/bin/upas/nedmail -S personal 497 | 5 messages 498 | : q 499 | $ $PLAN9/bin/upas/nedmail -S work 500 | 1 message 501 | : q 502 | $ 503 | ~~~~ 504 | 505 | When launching acme Mail we need to do something simmilar: 506 | 507 | ~~~~{.bash} 508 | upasname=my_personal@emailaddr.com 9 Mail -n personal 509 | upasname=my_work@emailaddr.com 9 Mail -n work 510 | ~~~~ 511 | 512 | To send emails we need to change our pipefrom script to select which 513 | server to use: 514 | 515 | ~~~~{.bash} 516 | #!/bin/bash 517 | 518 | if [ -z "$upasname" ]; then 519 | upasname="my_personal@emailaddr.com" 520 | fi 521 | 522 | case "$upasname" in 523 | "my_personal@emailaddr.com") 524 | server="tcp!imap.personal_provider.com!smtp" 525 | ;; 526 | "my_work@emailaddr.com") 527 | server="tcp!imap.work_provider.com!smtp" 528 | ;; 529 | esac 530 | 531 | cat | $PLAN9/bin/upas/smtp -sa -u $upasname $server $upasname $* 532 | 533 | ~~~~ 534 | 535 | As you can see, the ```upasname``` variable is used when launching acme 536 | Mail to know not only the ```From``` line, but also to know to which 537 | server is going to send our email. 538 | 539 | ### Accepting calendar events using ```nedmail``` 540 | 541 | When editing a maibox with ```nedmail``` we can reply to messages. And when replying to these messages we can pass arguments to ```marshal``` to include files. 542 | 543 | We have created a python script to generate a valid ical answer saving it in a temporary file which we will then attach to the reply of the email, answering to the event invitation with an accept, a decline, or tentatively accepted. 544 | 545 | ~~~~{.python} 546 | #!/usr/bin/env python3 547 | 548 | # A rewrite based on https://github.com/marvinthepa/mutt-ical 549 | 550 | import vobject 551 | import tempfile, time 552 | import os, sys 553 | import warnings 554 | from datetime import datetime 555 | from getopt import gnu_getopt as getopt 556 | 557 | usage=""" 558 | It reads an ical event invitation from stdin and generates 559 | an answer accepting, declining or tentatively accepting the event 560 | invitation. The invitation is tentatively accepted by default. 561 | 562 | It reads upasname environment variable by default, but other one 563 | can be indicated, ignoring the environment variable. 564 | 565 | It will output the nedmail command needed to reply to the message 566 | including the ical event answered. 567 | usage: 568 | %s [OPTIONS] [-e your@email.address] 569 | OPTIONS: 570 | -p print 571 | -a accept 572 | -d decline 573 | -t tentatively accept 574 | (print is default, last one wins) 575 | """ % sys.argv[0] 576 | 577 | def read_ics(): 578 | try: 579 | with warnings.catch_warnings(): 580 | warnings.simplefilter("ignore") 581 | invitation = vobject.readOne(sys.stdin, ignoreUnreadable=True) 582 | except AttributeError: 583 | invitation = vobject.readOne(sys.stdin, ignoreUnreadable=True) 584 | return invitation 585 | 586 | class Answer: 587 | def __init__(self, invitation, resp, email): 588 | # create 589 | ans = vobject.newFromBehavior('vcalendar') 590 | ans.add('method') 591 | ans.method.value = "REPLY" 592 | ans.add('vevent') 593 | 594 | for i in ["uid", "summary", "dtstart", "dtend", "organizer"]: 595 | if i in invitation.vevent.contents: 596 | ans.vevent.add( invitation.vevent.contents[i][0] ) 597 | 598 | # new timestamp 599 | ans.vevent.add('dtstamp') 600 | ans.vevent.dtstamp.value = datetime.utcnow().replace(tzinfo = invitation.vevent.dtstamp.value.tzinfo) 601 | 602 | ans.vevent.add('attendee') 603 | ans.vevent.attendee_list.pop() 604 | 605 | if 'attendee' in invitation.vevent.contents: 606 | atts = invitation.vevent.contents['attendee'] 607 | for a in atts: 608 | if self._get_email(a) == email: 609 | ans.vevent.attendee_list.append(self._set_resp(a,resp)) 610 | 611 | self.ans = ans 612 | 613 | @staticmethod 614 | def _get_email(att): 615 | if hasattr(att,'EMAIL_param'): 616 | return att.EMAIL_param 617 | else: 618 | return att.value.split(':')[1] 619 | 620 | @staticmethod 621 | def _set_resp(att, resp): 622 | att.params['PARTSTAT'] = [resp] 623 | for i in ["RSVP","ROLE","X-NUM-GUESTS","CUTYPE"]: 624 | if i in att.params: 625 | del att.params[i] 626 | return att 627 | 628 | def write(self): 629 | tempdir = tempfile.mkdtemp() 630 | icsfile = tempdir+"/event-reply.ics" 631 | with open(icsfile,"w") as f: 632 | f.write(self.ans.serialize()) 633 | return icsfile 634 | 635 | class Invitation: 636 | def __init__(self,ical): 637 | self.ics = ical 638 | contents = ical.vevent.contents 639 | self.title = contents['summary'][0].value 640 | if 'organizer' in ical.vevent.contents: 641 | if hasattr(ical.vevent.organizer,'EMAIL_param'): 642 | self.sender = ical.vevent.organizer.EMAIL_param 643 | else: 644 | self.sender = ical.vevent.organizer.value.split(':')[1] 645 | 646 | if 'description' in contents: 647 | self.desc = contents['description'][0].value 648 | 649 | if 'dtstart' in contents: 650 | self.start = contents['dtstart'][0].value.strftime("%m/%d/%Y, %H:%M:%S") 651 | 652 | if 'dtend' in contents: 653 | self.end = contents['dtend'][0].value.strftime("%m/%d/%Y, %H:%M:%S") 654 | 655 | if 'attendee' in contents: 656 | self.attendees = contents['attendee'] 657 | 658 | @staticmethod 659 | def _attendee(a): 660 | if hasattr(a, 'EMAIL_param'): 661 | att_mail = a.CN_param 662 | att_cn = a.EMAIL_param 663 | else: 664 | att_mail = a.value.split(':')[1] 665 | att_cn = a.value.split(':')[1] 666 | if a.CN_param: 667 | att_cn = a.CN_param 668 | 669 | return "\t" + att_cn + " <" + att_mail + ">" 670 | 671 | def __str__(self): 672 | r = map(self._attendee, self.attendees) 673 | to = "\n".join(r) 674 | return ("From: %s\n" 675 | "To:\n%s\n" 676 | "Title: %s\n" 677 | "When: from %s to %s\n" 678 | "Description:\n %s\n") % (self.sender, to, self.title, self.start, self.end, self.desc) 679 | 680 | if __name__=="__main__": 681 | email = os.environ['upasname'] 682 | resp = 'TENTATIVE' 683 | opts, args=getopt(sys.argv[1:],":epadt") 684 | 685 | invitation = Invitation(read_ics()) 686 | 687 | for opt,arg in opts: 688 | if opt == '-e': 689 | email = arg 690 | if opt == '-p': 691 | print(invitation) 692 | sys.exit() 693 | if opt == '-a': 694 | resp = 'ACCEPTED' 695 | if opt == '-d': 696 | resp = 'DECLINED' 697 | if opt == '-t': 698 | resp = 'TENTATIVE' 699 | 700 | ans = Answer(invitation.ics, resp, email) 701 | 702 | icsfile, tempdir = ans.write() 703 | 704 | print('r -a'+icsfile) 705 | ~~~~ 706 | 707 | The following session is an example on how to use the sciprt which we called ```acal```: 708 | 709 | ~~~~{.bash} 710 | $ upasname=gdiaz@-----.com nedmail -S work 711 | 9 messages 712 | 9: 9.2 713 | 714 | !--- cannot display messages of type application/ics 715 | 9.2: | acal -a 716 | r -a/tmp/tmpeiiutjwa/event-reply.ics 717 | ! 718 | 9.2: r -a/tmp/tmpeiiutjwa/event-reply.ics 719 | !$PLAN9/bin/upas/marshal -s 'Re: Invitación: Testing mar 3 de nov de 2020 20:30 - 21 :30 (CET) (gdiaz@-----.com)' -R mbox/12/2 -a/tmp/tmpeiiutjwa/event-reply.ics g.diaz@-----.com 720 | Accepting the message. 721 | slayer Nov 5 21:25:45 gdiaz@-----.com sent 1198 bytes to g.diaz@-----.com 722 | ! 723 | 9.2: 724 | $ 725 | ~~~~ 726 | 727 | 728 | #### Todo 729 | 730 | - Update ```ipso``` to work with an empty secstore 731 | - Replying to an email from [ned] does not work, becasue ```upas/marshal``` fails due to mailer being incorrectly set up. 732 | - How to work with calendar attachments, remainders and tasks, proposing new dates for a meeting, etc. 733 | - How to work with PGP email signatures, validating remote signatures, signing and encrypting our emails. 734 | 735 | [XDG_RUNTIME_DIR]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables 736 | [plan9port]: https://github.com/9fans/plan9port 737 | [Plan9]: https://plan9.io 738 | [secstored]: https:///plan9.io/magic/man2html/8/secstore 739 | [factotum]: https:///plan9.io/magic/man2html/4/factotum 740 | [upas/fs]: https://plan9.io/magic/man2html/4/upasfs 741 | [mailfs]: https://github.com/9fans/plan9port/tree/master/src/cmd/upas/nfs 742 | [upas/smtp]: https://plan9.io/magic/man2html/8/smtp 743 | [upas]: http://doc.cat-v.org/bell_labs/upas_mail_system/upas.pdf 744 | [acme]: https://plan9.io/magic/man2html/1/acme 745 | [ned]: https://plan9.io/magic/man2html/1/nedmail 746 | [msmtp]: https://marlam.de/msmtp/ 747 | [wiki]: https://plan9.io/wiki/plan9/mail_configuration/index.html 748 | [ndb]: https://9fans.github.io/plan9port/man/man7/ndb.html 749 | [network database]: https://plan9.io/magic/man2html/8/ndb 750 | -------------------------------------------------------------------------------- /lib/plumbing: -------------------------------------------------------------------------------- 1 | # to update: cat $HOME/lib/plumbing | 9p write plumb/rules 2 | 3 | editor = acme 4 | 5 | kind is text 6 | data matches '[a-zA-Z0-9_\-./~{}@]+('$addr')?' 7 | data matches '((/[a-zA-Z0-9_\-./]+)@[a-zA-Z0-9_\-./~{}@]+)('$addr')?' 8 | data set $1 9 | arg isdir $2 10 | attr add addr=$4 11 | plumb to gitfileedit 12 | plumb client Gitfiles 13 | 14 | type is text 15 | data matches '[a-zA-Z0-9_\-./]+' 16 | data matches '([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])[0-9a-f]*' 17 | plumb start rc -c 'cd '''$wdir'''; root=`{git rev-parse --show-toplevel}; rev='''$1'''; {gitfileshow $rev} >[2=1] | nobs | plumb -i -d edit -a ''action=showdata filename=''$root/+$rev' 18 | 19 | # declarations of ports without rules 20 | plumb to lsp 21 | 22 | type is text 23 | data matches '[a-zA-Z0-9_\-./@]+' 24 | data matches '([a-zA-Z0-9_\-./@]+)\.(pdf|PDF|epub|XPS|xps)' 25 | arg isfile $0 26 | plumb to pdf 27 | plumb start xdg-open $file 28 | 29 | type is text 30 | data matches '[a-zA-Z0-9_\-./@]+' 31 | data matches '([a-zA-Z0-9_\-./@]+)\.(jpe?g|JPE?G|gif|GIF|tiff?|TIFF?|ppm|bit|png|PNG)' 32 | arg isfile $0 33 | plumb to image 34 | plumb start xdg-open $file 35 | 36 | type is text 37 | data matches '.*.md' 38 | arg isfile $0 39 | plumb to editor 40 | plumb start B $file 41 | 42 | type is text 43 | data matches '(https?|ftp|file|news|nntp|telnet|wais|prospero)://.*' 44 | plumb to web 45 | plumb start xdg-open $0 46 | 47 | include basic 48 | -------------------------------------------------------------------------------- /lib/profile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rc 2 | 3 | umask 077 4 | 5 | # assume the parent shell set up a HOME and USER variable 6 | # correctly, in case of using rc as a login shell 7 | # this might not work 8 | home=$HOME 9 | user=$USER 10 | 11 | path=(/usr/sbin /sbin /usr/local/bin /bin /usr/bin) 12 | 13 | fn nssetup { 14 | if(9 test ! -d $home/.ns/$1) { 15 | mkdir -p $home/.ns/$1 16 | } 17 | echo $home/.ns/$1 18 | } 19 | 20 | # set plan9 environment 21 | PLAN9=/usr/local/plan9 22 | P9PENV=$home/.local/p9penv 23 | . $PLAN9/lib/acme.rc 24 | 25 | # mk max concurrent procs 26 | nproc=8 27 | 28 | # set golang environment 29 | GOVERSION=1.21.3 30 | GOROOT=$home/.local/go/$GOVERSION 31 | GOPATH=$home/go 32 | GO111MODULE=on 33 | 34 | # set acme environment 35 | usebigarrow=1 36 | EDITOR=editinacme 37 | PAGER=nobs 38 | 39 | # things for xterm 40 | # set cursor to a steady bar | 41 | # printf '\033[6 q' 42 | # set cursor to a steady block 43 | # echo -e -n '\x1b[\x30 q' 44 | # GNUTERM='sixelgd size 1280,720 truecolor font 'DEC Terminal Modern' 14' 45 | 46 | # set aliases 47 | fn tb { nc termbin.com 9999 } 48 | 49 | # Prepare PATH environment 50 | # append custom tools at the end of the current path 51 | # prepend ~/bin and goroot into path to avoid using gcc-go in system path by default 52 | pathappend=($P9PENV/mail $GOPATH/bin $PLAN9/bin/upas) 53 | pathprepend=($P9PENV/bin $PLAN9/bin $home/.local/bin $GOROOT/bin /opt/homebrew/bin) 54 | 55 | path=($pathprepend $path $pathappend) 56 | 57 | # check if something is not there 58 | dirs=($home/lib $PLAN9 $P9PENV) 59 | for(dir in $dirs) { 60 | if(9 test ! -r $dir) { 61 | echo $dir 'does not exists. Verify set up.' 62 | exit 63 | } 64 | } 65 | 66 | files=($home/lib/plumbing) 67 | for(f in $files) { 68 | if (9 test ! -f $f) { 69 | echo $f 'does not exists. Verify set up' 70 | } 71 | } 72 | 73 | NAMESPACE=`{nssetup 0} 74 | 75 | # ssh agent set up 76 | 77 | SSH_ENV=$home/.ssh/environment 78 | 79 | fn export {} 80 | 81 | fn startsshagent { 82 | echo 'Initialising new SSH agent...' 83 | /usr/bin/ssh-agent | sed 's/^echo/#echo/' > $SSH_ENV 84 | echo succeeded 85 | chmod 600 $SSH_ENV 86 | . $SSH_ENV> /dev/null 87 | /usr/bin/ssh-add; 88 | } 89 | 90 | # Source SSH settings, if applicable 91 | 92 | if(test -f $SSH_ENV) { 93 | . $SSH_ENV> /dev/null 94 | pgrep ssh-agent > /dev/null 95 | switch($status) { 96 | case 1 97 | startsshagent 98 | } 99 | } 100 | if not { 101 | startsshagent 102 | } 103 | 104 | prompt='» ' 105 | nl=' 106 | ' 107 | 108 | fn title { 109 | text=`{pwd} 110 | label $"text 111 | } 112 | 113 | # set cd to execute awd when in acme win 114 | fn cd { 115 | builtin cd $* && title 116 | } 117 | 118 | 119 | fn _set_font { 120 | family=$1 121 | shift 122 | size=$1 123 | shift 124 | hidpi=$1 125 | shift 126 | 127 | switch($family) { 128 | case go 129 | mono='GoMono' 130 | sans='GoRegular' 131 | case input 132 | mono='InputMono-Regular' 133 | sans='InputSans-Regular' 134 | case iosevka 135 | mono='Iosevka' 136 | sans='Iosevka-Aile' 137 | case sf 138 | mono='SFMono-Regular' 139 | sans='SFProDisplay-Regular' 140 | case * 141 | mono='DejaVuSansMono' 142 | sans='DejaVuSans' 143 | } 144 | 145 | fixedfont='/mnt/font/'$mono'/'$size'a/font' 146 | font='/mnt/font/'$sans'/'$size'a/font' 147 | hidpifixedfont='/mnt/font/'$mono'/'$hidpi'a/font' 148 | hidpifont='/mnt/font/'$sans'/'$hidpi'a/font' 149 | } 150 | 151 | # start new p9p session 152 | # start factotum before secstore so it does not prompt for a password 153 | # load secrets manually using ipso 154 | fn p9p_session { 155 | NAMESPACE=`{namespace} 156 | mkdir -p $NAMESPACE 157 | 158 | for(proc in fontsrv factotum secstored plumber) { 159 | pgrep '^'^$proc > /dev/null 160 | switch($status) { 161 | case 1 162 | $PLAN9/bin/9 $proc & 163 | } 164 | } 165 | } 166 | 167 | # default font is dejavu sans 168 | # _set_font default 8 16 169 | _set_font go 8 16 170 | 171 | # always set up the p9p session, 172 | # this will start services only if there are not started yet 173 | p9p_session 174 | 175 | # default acme options 176 | fn acme { 177 | SHELL=rc $PLAN9/bin/acme -a -c 1 -f $font,$hidpifont -F $fixedfont,$hidpifixedfont $* 178 | } 179 | -------------------------------------------------------------------------------- /mail/acal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # A rewrite based on https://github.com/marvinthepa/mutt-ical 4 | 5 | import vobject 6 | import tempfile, time 7 | import os, sys 8 | import warnings 9 | from datetime import datetime 10 | from getopt import gnu_getopt as getopt 11 | 12 | usage=""" 13 | It reads an ical event invitation from stdin and generates 14 | an answer accepting, declining or tentatively accepting the event 15 | invitation. The invitation is tentatively accepted by default. 16 | 17 | It reads upasname environment variable by default, but other one 18 | can be indicated, ignoring the environment variable. 19 | 20 | It will output the nedmail command needed to reply to the message 21 | including the ical event answered. 22 | usage: 23 | %s [OPTIONS] [-e your@email.address] 24 | OPTIONS: 25 | -p print 26 | -a accept 27 | -d decline 28 | -t tentatively accept 29 | (print is default, last one wins) 30 | """ % sys.argv[0] 31 | 32 | def read_ics(): 33 | try: 34 | with warnings.catch_warnings(): 35 | warnings.simplefilter("ignore") 36 | invitation = vobject.readOne(sys.stdin, ignoreUnreadable=True) 37 | except AttributeError: 38 | invitation = vobject.readOne(sys.stdin, ignoreUnreadable=True) 39 | return invitation 40 | 41 | class Answer: 42 | def __init__(self, invitation, resp, email): 43 | # create 44 | ans = vobject.newFromBehavior('vcalendar') 45 | ans.add('method') 46 | ans.method.value = "REPLY" 47 | ans.add('vevent') 48 | 49 | for i in ["uid", "summary", "dtstart", "dtend", "organizer"]: 50 | if i in invitation.vevent.contents: 51 | ans.vevent.add( invitation.vevent.contents[i][0] ) 52 | 53 | # new timestamp 54 | ans.vevent.add('dtstamp') 55 | ans.vevent.dtstamp.value = datetime.utcnow().replace(tzinfo = invitation.vevent.dtstamp.value.tzinfo) 56 | 57 | ans.vevent.add('attendee') 58 | ans.vevent.attendee_list.pop() 59 | 60 | if 'attendee' in invitation.vevent.contents: 61 | atts = invitation.vevent.contents['attendee'] 62 | for a in atts: 63 | if self._get_email(a) == email: 64 | ans.vevent.attendee_list.append(self._set_resp(a,resp)) 65 | 66 | self.ans = ans 67 | 68 | @staticmethod 69 | def _get_email(att): 70 | if hasattr(att,'EMAIL_param'): 71 | return att.EMAIL_param 72 | else: 73 | return att.value.split(':')[1] 74 | 75 | @staticmethod 76 | def _set_resp(att, resp): 77 | att.params['PARTSTAT'] = [resp] 78 | for i in ["RSVP","ROLE","X-NUM-GUESTS","CUTYPE"]: 79 | if i in att.params: 80 | del att.params[i] 81 | return att 82 | 83 | def write(self): 84 | tempdir = tempfile.mkdtemp() 85 | icsfile = tempdir+"/event-reply.ics" 86 | with open(icsfile,"w") as f: 87 | f.write(self.ans.serialize()) 88 | return icsfile 89 | 90 | class Invitation: 91 | def __init__(self,ical): 92 | self.ics = ical 93 | contents = ical.vevent.contents 94 | self.title = contents['summary'][0].value 95 | if 'organizer' in ical.vevent.contents: 96 | if hasattr(ical.vevent.organizer,'EMAIL_param'): 97 | self.sender = ical.vevent.organizer.EMAIL_param 98 | else: 99 | self.sender = ical.vevent.organizer.value.split(':')[1] 100 | 101 | if 'description' in contents: 102 | self.desc = contents['description'][0].value 103 | 104 | if 'dtstart' in contents: 105 | self.start = contents['dtstart'][0].value.strftime("%m/%d/%Y, %H:%M:%S") 106 | 107 | if 'dtend' in contents: 108 | self.end = contents['dtend'][0].value.strftime("%m/%d/%Y, %H:%M:%S") 109 | 110 | if 'attendee' in contents: 111 | self.attendees = contents['attendee'] 112 | 113 | @staticmethod 114 | def _attendee(a): 115 | if hasattr(a, 'EMAIL_param'): 116 | att_mail = a.CN_param 117 | att_cn = a.EMAIL_param 118 | else: 119 | att_mail = a.value.split(':')[1] 120 | att_cn = a.value.split(':')[1] 121 | if a.CN_param: 122 | att_cn = a.CN_param 123 | 124 | return "\t" + att_cn + " <" + att_mail + ">" 125 | 126 | def __str__(self): 127 | r = map(self._attendee, self.attendees) 128 | to = "\n".join(r) 129 | return ("From: %s\n" 130 | "To:\n%s\n" 131 | "Title: %s\n" 132 | "When: from %s to %s\n" 133 | "Description:\n %s\n") % (self.sender, to, self.title, self.start, self.end, self.desc) 134 | 135 | if __name__=="__main__": 136 | email = os.environ['upasname'] 137 | resp = 'TENTATIVE' 138 | opts, args=getopt(sys.argv[1:],":epadt") 139 | 140 | invitation = Invitation(read_ics()) 141 | 142 | for opt,arg in opts: 143 | if opt == '-e': 144 | email = arg 145 | if opt == '-p': 146 | print(invitation) 147 | sys.exit() 148 | if opt == '-a': 149 | resp = 'ACCEPTED' 150 | if opt == '-d': 151 | resp = 'DECLINED' 152 | if opt == '-t': 153 | resp = 'TENTATIVE' 154 | 155 | ans = Answer(invitation.ics, resp, email) 156 | 157 | icsfile = ans.write() 158 | 159 | print('r -a'+icsfile) 160 | -------------------------------------------------------------------------------- /mail/acal.rc: -------------------------------------------------------------------------------- 1 | #!/usr/local/plan9/bin/rc 2 | # 3 | # Reads a calendar invitation from stdin 4 | # and writes a temporary file with a calendar event answering 5 | # to the event invitation with an accept, a decline, or 6 | # tentatively accepted. 7 | # 8 | # 9 | timestamp=`{date +%Y%m%dT%H%M%SZ} 10 | 11 | path=($PLAN9/bin $path) 12 | 13 | switch($*){ 14 | case -a 15 | answer="ACCEPTED" 16 | case -d 17 | answer="DECLINED" 18 | case * 19 | answer="TENTATIVE" 20 | } 21 | 22 | 23 | # fold and unfold 24 | # https://tools.ietf.org/html/rfc5545#section-3.1 25 | fn fold { 26 | awk '{gsub(/.{75}/,"&\r\n")}1' 27 | } 28 | 29 | fn unfold { 30 | tr '\x0d\x0a ' '%' | sed 's/%%%//g' | sed 's/%%/\n/g' | sed 's/%/ /g' 31 | } 32 | 33 | 34 | # How to start an ical event reply 35 | fn begin { 36 | echo -n 'BEGIN:VCALENDAR 37 | VERSION:2.0 38 | METHOD:REPLY 39 | PRODID:-//p9penv//plan9port AWK//EN 40 | BEGIN:VEVENT 41 | ' 42 | } 43 | 44 | fn answer { 45 | awk -v answer=$answer -v ts=$timestamp -v upasname=$upasname -v answer="ACCEPT" ' 46 | BEGIN { 47 | fparams["ATTENDEE"]=1 48 | fparams["RSVP"]=1 49 | fparams["ROLE"]=1 50 | fparams["X-NUM-GUESTS"]=1 51 | fparams["CUTYPE"]=1 52 | } 53 | /^UID/ { printf "%s\r\n", $0 } 54 | /^DTSTART/ { printf "%s\r\n", $0 } 55 | /^DTEND/ { printf "%s\r\n", $0 } 56 | /^ATTENDEE/ { 57 | # attendee is params:mailto:email address 58 | split($0, attendee,":") 59 | # params is attendee;key1=value1;key2=value2.... 60 | split(attendee[1],params,";") 61 | for(k in params) { 62 | split(params[k],param,"=") 63 | if (!(param[1] in fparams)) { 64 | validparams[param[1]]=param[2] 65 | } 66 | } 67 | validparams["PARTSTAT"]=answer 68 | if (attendee[3] ~ upasname) { 69 | str="ATTENDEE" 70 | for(k in validparams) { 71 | str = str ";" k "=" validparams[k] 72 | } 73 | printf "%s:mailto:%s\r\n", str,upasname 74 | } 75 | } 76 | /^DTSTAMP/ { 77 | printf "DTSTAMP:%s\r\n", ts 78 | } 79 | /^ORGANIZER/ { printf "%s\r\n", $0 } 80 | /^SUMMARY/ { printf "%s\r\n", $0 } 81 | ' 82 | } 83 | 84 | fn end { 85 | echo ' 86 | END:VEVENT 87 | END:VCALENDAR 88 | ' 89 | } 90 | 91 | 92 | { 93 | begin 94 | unfold | answer 95 | end 96 | } | fold | grep -v -e '^$' 97 | -------------------------------------------------------------------------------- /mail/pipefrom: -------------------------------------------------------------------------------- 1 | #!/usr/local/plan9/bin/rc 2 | # 3 | # Search $upasname in factotum as if it were an user. If the service 4 | # of the user is smtp, use that server to send emails. 5 | # 6 | path=($PLAN9/bin $path) 7 | ifs=' 8 | ' 9 | server=`{9p read factotum/ctl | 9 sed 's/([a-z]+)=//g' | grep smtp | grep $upasname | awk '{print $4 }' } 10 | switch($#server) { 11 | case 0 12 | echo "Fill factotum with smtp credentials for $upasname user" 13 | exit 14 | case * 15 | cat | $PLAN9/bin/upas/smtp -sa -u $upasname $server $upasname $* 16 | } 17 | -------------------------------------------------------------------------------- /screenshots/simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gdiazlo/p9penv/d55e9436a0a1ec026b5dc34b964d734a5c8de3ee/screenshots/simple.png --------------------------------------------------------------------------------