├── .gitattributes ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── all-packages.bat ├── all-packages.conf ├── extra-packages.bat ├── extra-packages.conf ├── preset-packages.bat ├── preset-packages.conf ├── rime-install ├── rime-install-bootstrap.bat ├── rime-install-config.bat ├── rime-install.bat └── scripts ├── bootstrap.sh ├── fetch-package.sh ├── frontend.sh ├── install-packages.sh ├── minimal-build.sh ├── recipe.sh ├── resolver.sh ├── selector.sh ├── split-packages.sh ├── styles.sh └── update-package.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.bat text eol=crlf 3 | *.conf text eol=lf 4 | *.sh text eol=lf 5 | rime-install text eol=lf 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | /package 3 | /output 4 | plum-*.tar.gz -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(SRCDIR),) 2 | SRCDIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) 3 | endif 4 | 5 | # Tips: you can set OUTPUT to Rime user directory in the command line 6 | ifeq ($(OUTPUT),) 7 | OUTPUT := $(SRCDIR)/output 8 | endif 9 | 10 | ifeq ($(PREFIX),) 11 | PREFIX := /usr 12 | endif 13 | 14 | ifeq ($(RIME_DATA_DIR),) 15 | RIME_DATA_DIR := $(PREFIX)/share/rime-data 16 | endif 17 | 18 | .DEFAULT_GOAL := preset 19 | 20 | preset extra all: clean 21 | bash $(SRCDIR)/scripts/install-packages.sh :$@ $(OUTPUT) 22 | 23 | minimal: clean 24 | bash $(SRCDIR)/scripts/minimal-build.sh $(OUTPUT) 25 | 26 | preset-bin: preset 27 | $(MAKE) build 28 | 29 | all-bin: all 30 | $(MAKE) build 31 | 32 | minimal-bin: minimal 33 | $(MAKE) build 34 | 35 | build: 36 | rime_deployer --build $(OUTPUT) 37 | rm $(OUTPUT)/user.yaml 38 | 39 | install: 40 | @echo "Installing Rime data to '$(DESTDIR)$(RIME_DATA_DIR)'." 41 | @install -d $(DESTDIR)$(RIME_DATA_DIR) 42 | @install -m 644 $(OUTPUT)/*.* $(DESTDIR)$(RIME_DATA_DIR) 43 | @if [ -d "$(OUTPUT)/build" ]; then \ 44 | install -d $(DESTDIR)$(RIME_DATA_DIR)/build; \ 45 | install -m 644 $(OUTPUT)/build/*.* $(DESTDIR)$(RIME_DATA_DIR)/build; \ 46 | fi 47 | @if [ -d "$(OUTPUT)/opencc" ]; then \ 48 | install -d $(DESTDIR)$(RIME_DATA_DIR)/opencc; \ 49 | install -m 644 $(OUTPUT)/opencc/*.* $(DESTDIR)$(RIME_DATA_DIR)/opencc; \ 50 | fi 51 | 52 | clean: 53 | rm -rf $(OUTPUT) > /dev/null 2>&1 || true 54 | 55 | VERSION = $(shell date "+%Y%m%d") 56 | 57 | # A source tarball that includes all data packages. 58 | # To reproduce package contents of the release, set `no_update=1`: 59 | # tar xzf plum-YYYYMMDD.tar.gz 60 | # cd plum 61 | # no_update=1 make 62 | # sudo make install 63 | dist: 64 | $(MAKE) OUTPUT=$(OUTPUT) all 65 | tar czf plum-$(VERSION).tar.gz \ 66 | --exclude=.git \ 67 | --exclude=output \ 68 | --exclude='plum-*.tar.gz' \ 69 | -C .. plum 70 | 71 | .PHONY: preset extra all minimal \ 72 | preset-bin all-bin minimal-bin \ 73 | build install clean dist 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 東風破 /plum/ 4 | 5 | Rime configuration manager and input schema repository 6 | 7 | ## Project home 8 | 9 | [rime.im](https://rime.im) 10 | 11 | ## Introduction 12 | 13 | **/plum/** is a configuration manager for [Rime](https://rime.im) input method engine. 14 | 15 | /// **東風破** 是 [中州韻輸入法引擎](https://rime.im) 的配置管理工具。/// 16 | 17 | It's designed for Rime users to install and update the default configuration and a collection 18 | of data packages maintained by [Rime Developers](https://github.com/rime). 19 | 20 | It also works perfectly well with personal configuration hosted on GitHub and input schema packages 21 | from third-party developers. 22 | 23 | A **Rime input schema** (**Rime 輸入方案**) defines the rules of a specific "input method", or in technical terms 24 | how user input sequences are interpreted by the Rime input method engine. 25 | It consists of a configuration file named `.schema.yaml`, and usually an optional 26 | **Rime dictionary** (**韻書**) file named `*.dict.yaml`. 27 | 28 | A package may contain one or several interrelated input schemata and their affiliated Rime dictionaries. 29 | A package is also good for publishing general configuration files and data files used by Rime. 30 | 31 | In /plum/ terms, a re-usable piece of configuration is known as a **recipe** (**配方**), denoted by the "℞" symbol. 32 | 33 | A data package itself can be a recipe, this is the common case. 34 | In the future, /plum/ will support more fine-grained recipes that allow you to select what to install from a package, 35 | or even take parameters like the target input schema to customize. 36 | 37 | ## Packages 38 | 39 | This is an index of the packages maintained by Rime Developers as separate projects. 40 | 41 | These packages aim to offer a sensible default configuration for most users, and support various 42 | Chinese input methods including those based on modern dialects and historical Chinese phonology. 43 | 44 | /// **配方一覽** /// 45 | 46 | ### Essentials 47 | 48 | - ℞ [`prelude`](https://github.com/rime/rime-prelude): 基礎配置 / the prelude package, providing Rime's default settings 49 | - ℞ [`essay`](https://github.com/rime/rime-essay): 八股文 / a shared vocabulary and language model 50 | 51 | ### Phonetic-based input methods 52 | 53 | Modern Standard Mandarin 54 | 55 | - ℞ [`luna-pinyin`](https://github.com/rime/rime-luna-pinyin): 朙月拼音 / Pinyin input method for Traditional Chinese 56 | - ℞ [`terra-pinyin`](https://github.com/rime/rime-terra-pinyin): 地球拼音 / School-taught Pinyin, with tone marks 57 | - ℞ [`bopomofo`](https://github.com/rime/rime-bopomofo): 注音 / Zhuyin (aka. Bopomofo) 58 | - ℞ [`pinyin-simp`](https://github.com/rime/rime-pinyin-simp): 袖珍簡化字拼音 59 | 60 | Derivatives of Pinyin 61 | 62 | - ℞ [`double-pinyin`](https://github.com/rime/rime-double-pinyin): 雙拼 / Double Pinyin (ZiRanMa, ABC, flyPY, MSPY, PYJJ variants) 63 | - ℞ [`combo-pinyin`](https://github.com/rime/rime-combo-pinyin): 宮保拼音 / [Combo Pinyin](https://github.com/rime/home/wiki/ComboPinyin), a chord-typing input method 64 | - ℞ [`stenotype`](https://github.com/rime/rime-stenotype): 打字速記法 / a stenographic system derived from ABC Easy Shorthand 65 | 66 | Other modern varieties of Chinese 67 | 68 | - ℞ [`cantonese`](https://github.com/rime/rime-cantonese): 粵語拼音 / Cantonese 69 | - ℞ [`jyutping`](https://github.com/rime/rime-jyutping): 粵拼(無聲調) / Cantonese (without tones) 70 | - ℞ [`wugniu`](https://github.com/rime/rime-wugniu): 上海吳語 / Wu (Shanghainese) 71 | - ℞ [`soutzoe`](https://github.com/rime/rime-soutzoe): 蘇州吳語 / Wu (Suzhounese) 72 | 73 | Middle Chinese 74 | 75 | - ℞ [`middle-chinese`](https://github.com/rime/rime-middle-chinese): 中古漢語拼音 / Middle Chinese Romanization 76 | 77 | ### Shape-based input methods 78 | 79 | - ℞ [`stroke`](https://github.com/rime/rime-stroke): 五筆畫 / five strokes 80 | - ℞ [`cangjie`](https://github.com/rime/rime-cangjie): 倉頡輸入法 / Cangjie input method 81 | - ℞ [`quick`](https://github.com/rime/rime-quick): 速成 / Simplified Cangjie 82 | - ℞ [`wubi`](https://github.com/rime/rime-wubi): 五筆字型 83 | - ℞ [`array`](https://github.com/rime/rime-array): 行列輸入法 84 | - ℞ [`scj`](https://github.com/rime/rime-scj): 快速倉頡 85 | 86 | ### Miscellaneous 87 | 88 | - ℞ [`emoji`](https://github.com/rime/rime-emoji): 繪文字 / input emoji with English or Chinese Pinyin keywords 89 | - ℞ [`ipa`](https://github.com/rime/rime-ipa): 國際音標 / International Phonetic Alphabet 90 | 91 | ## Usage 92 | 93 | To prepare your Rime configuration for [ibus-rime](https://github.com/rime/ibus-rime), 94 | [Squirrel](https://github.com/rime/squirrel), you can get started by running 95 | 96 | ```sh 97 | curl -fsSL https://raw.githubusercontent.com/rime/plum/master/rime-install | bash 98 | ``` 99 | 100 | /// 用法:Linux、macOS 系統,在終端輸入以上命令行,安裝配置管理器及預設配方。 /// 101 | 102 | Paste the command line in Linux terminal or macOS `Terminal.app` and hit enter. 103 | 104 | The one-liner runs the `rime-install` script to download preset packages and install 105 | source files to Rime user directory. (Yet it doesn't enable new schemas for you) 106 | 107 | For [Weasel](https://github.com/rime/weasel), please refer to the [Windows bootstrap script](#windows) section for initial setup. 108 | 109 | ## Advanced usage 110 | 111 | Alternatively, you can specify a configuration among `:preset`, `:extra` and `:all` (note the colon): 112 | 113 | ```sh 114 | curl -fsSL https://raw.githubusercontent.com/rime/plum/master/rime-install | bash -s -- :preset 115 | ``` 116 | 117 | This is equivalent to cloning this repo and running the local copy of `rime-install`: 118 | 119 | ```sh 120 | git clone --depth 1 https://github.com/rime/plum.git 121 | cd plum 122 | bash rime-install :preset 123 | ``` 124 | 125 | You can then add packages from all the great Rime developers on GitHub by specifying 126 | a list of package names or refer to packages by `/`: 127 | 128 | ```sh 129 | bash rime-install jyutping lotem/rime-zhung acevery/rime-zhengma 130 | 131 | # optionally, specific a branch by appending "@" 132 | bash rime-install jyutping@master lotem/rime-zhung@master 133 | ``` 134 | 135 | Lastly, it's also possible to install other author's Rime configuration from a 136 | `*-packages.conf` file hosted on GitHub. For example: 137 | 138 | 139 | ```sh 140 | bash rime-install https://github.com/lotem/rime-forge/raw/master/lotem-packages.conf 141 | 142 | # or in short form: "//" 143 | bash rime-install lotem/rime-forge/lotem-packages.conf 144 | 145 | # or specify a branch: "/@/" 146 | bash rime-install lotem/rime-forge@master/lotem-packages.conf 147 | ``` 148 | 149 | For third-party Rime distributions, specify the `rime_frontend` variable in the command line: 150 | 151 | ```sh 152 | rime_frontend=fcitx-rime bash rime-install 153 | ``` 154 | 155 | or set `rime_dir` to Rime user directory 156 | 157 | ```sh 158 | rime_dir="$HOME/.config/fcitx/rime" bash rime-install 159 | ``` 160 | 161 | To update /plum/ itself, run 162 | 163 | ```sh 164 | bash rime-install plum 165 | ``` 166 | 167 | ## Interactively select packages to install 168 | 169 | Specify the `--select` flag as the first argument to `rime-install`, 170 | then add configurations (`:preset` is the default) and/or individual packages to display in the menu. 171 | 172 | ```sh 173 | bash rime-install --select :extra 174 | 175 | bash rime-install --select :all lotem/rime-forge/lotem-packages.conf 176 | ``` 177 | 178 | [Screenshot](https://github.com/rime/home/raw/master/images/rime-install-select.png) of usage example 179 | 180 | 181 | ## Windows bootstrap script 182 | 183 | To get started on Windows, download the [bootstrap bundle][bootstrap-bundle], 184 | unpack the ZIP archive and run `rime-install-bootstrap.bat` for initial setup. 185 | 186 | It will fetch the latest installer script `rime-install.bat` an create a shortcut to it, 187 | which can then be copied or moved anywhere for easier access. 188 | 189 | /// Windows 用家可以通過 [小狼毫](https://rime.im/download/#windows) 0.11 以上「輸入法設定/獲取更多輸入方案」調用配置管理器。/// 190 | 191 | /// 或者下載獨立的 [啓動工具包][bootstrap-bundle]。/// 192 | 193 | [bootstrap-bundle]: https://github.com/rime/plum-windows-bootstrap/archive/master.zip 194 | 195 | ### Use built-in ZIP package installer 196 | 197 | You can use the installer script to download and install ZIP packages from GitHub, in a number of ways: 198 | 199 | 1. Double-click the shortcut to bring up an interactive package installer, then input package name, `/` or GitHub URL for the package. 200 | 201 | 2. Run `rime-install.bat` in the command line. The command takes a list of packages to install as arguments. 202 | 203 | ```batch 204 | rime-install :preset combo-pinyin jyutping wubi 205 | ``` 206 | 207 | 3. Drag downloaded ZIP packages from GitHub onto the shortcut to do offline install. 208 | 209 | You can find ZIP packages downloaded by the installer script in `%TEMP%` folder (can be customized via variable `download_cache_dir`). 210 | 211 | To manually download ZIP package from a GitHub repository, click the button *Clone or download*, then *Download ZIP*. 212 | 213 | ### Use git for incremental updates (optional) 214 | 215 | If [Git for Windows](https://gitforwindows.org/) is installed in the default location or is available in your `PATH`, 216 | the script will use git-bash to install or update packages. 217 | 218 | Use the following command to install Git for Windows, if you are new to git. 219 | 220 | ```batch 221 | rime-install git 222 | ``` 223 | 224 | You can set more options in `rime-install-config.bat` in the same directory as `rime-install.bat`, for example: 225 | 226 | ```batch 227 | set plum_dir=%APPDATA%\plum 228 | set rime_dir=%APPDATA%\Rime 229 | set use_plum=1 230 | ``` 231 | 232 | ## Install as shared data 233 | 234 | The `Makefile` builds and installs Rime data as a software on Unix systems. 235 | 236 | For downstream packagers for the package management systems of the OS, it's recommend to create 237 | separate packages for the /plum/ configuration manager (possibly named `rime-plum` or `rime-install`) 238 | and the data package(s) (possibly named `rime-data`, or `rime-data-*` if separated into many) 239 | created by the make targets. 240 | 241 | ### Build dependencies 242 | 243 | - git 244 | - librime>=1.3 (for `rime_deployer`) 245 | 246 | ### Run-time dependencies 247 | 248 | - librime>=1.3 249 | - opencc>=1.0.2 250 | 251 | ### Build and install 252 | 253 | The default make target uses `git` command to download the latest packages from GitHub. 254 | 255 | ```sh 256 | make 257 | sudo make install 258 | ``` 259 | 260 | You can optionally build the by default enabled input schemas to binaries. 261 | This saves user's time building those files on first startup. 262 | 263 | ```sh 264 | make preset-bin 265 | ``` 266 | 267 | ## License 268 | 269 | Code in the `rime/plum` repository is licensed under **LGPLv3**. 270 | Please refer to the `LICENSE` file in the project root directory. 271 | 272 | **Note** that make targets provided by the `Makefile` may include files downloaded by the 273 | configuration manager. Individual packages can be released under different licenses. 274 | Please refer to their respective `LICENSE` files. 275 | The license compatible with all the maintained packages is **GPLv3**. 276 | 277 | ## Credits 278 | 279 | We are grateful to the makers of the following open source projects: 280 | 281 | - [Android Pinyin IME](https://source.android.com/) (Apache 2.0) 282 | - [Chewing / 新酷音](http://chewing.im/) (LGPL) 283 | - [ibus-table](https://github.com/acevery/ibus-table) (LGPL) 284 | - [OpenCC / 開放中文轉換](https://github.com/BYVoid/OpenCC) (Apache 2.0) 285 | - [moedict / 萌典](https://www.moedict.tw) (CC0 1.0) 286 | - [Rime 翰林院 / Rime Academy](https://github.com/rime-aca) (GPLv3) 287 | 288 | Also to the inventors of the following input methods: 289 | 290 | - Cangjie / 倉頡輸入法 by 朱邦復 291 | - Array input method / 行列輸入法 by 廖明德 292 | - Wubi / 五筆字型 by 王永民 293 | - Scj / 快速倉頡 by 麥志洪 294 | - Middle Chinese Romanization / 中古漢語拼音 by 古韻 295 | 296 | ## Contributors 297 | 298 | This software is a result of collective effort. It was set up by the following 299 | people by contributing files, patches and pull-requests. See also the 300 | [contributors](https://github.com/rime/plum/graphs/contributors) page for a 301 | list of open-source collaborators. 302 | 303 | - [佛振](https://github.com/lotem) 304 | - [Kunki Chou](https://github.com/kunki) 305 | - [雪齋](https://github.com/LEOYoon-Tsaw) 306 | - [Patrick Tschang](https://github.com/Patricivs) 307 | - [Joseph J.C. Tang](https://github.com/jinntrance) 308 | - [lxk](http://101reset.com) 309 | - [Ye Zhou](https://github.com/zhouye) 310 | - Jiehong Ma 311 | - StarSasumi 312 | - 古韻 313 | - 寒寒豆 314 | - 四季的風 315 | - 上海閒話abc 316 | - 吳語越音 317 | -------------------------------------------------------------------------------- /all-packages.bat: -------------------------------------------------------------------------------- 1 | set package_list= 2 | call preset-packages.bat 3 | call extra-packages.bat 4 | -------------------------------------------------------------------------------- /all-packages.conf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | package_list=() 4 | 5 | source "${root_dir:-.}"/preset-packages.conf 6 | source "${root_dir:-.}"/extra-packages.conf 7 | -------------------------------------------------------------------------------- /extra-packages.bat: -------------------------------------------------------------------------------- 1 | set package_list=%package_list%^ 2 | array^ 3 | cantonese^ 4 | combo-pinyin^ 5 | double-pinyin^ 6 | emoji^ 7 | ipa^ 8 | jyutping^ 9 | middle-chinese^ 10 | pinyin-simp^ 11 | quick^ 12 | scj^ 13 | soutzoe^ 14 | stenotype^ 15 | wubi^ 16 | wugniu^ 17 | -------------------------------------------------------------------------------- /extra-packages.conf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | package_list+=( 4 | array 5 | cantonese 6 | combo-pinyin 7 | double-pinyin 8 | emoji 9 | ipa 10 | jyutping 11 | middle-chinese 12 | pinyin-simp 13 | quick 14 | scj 15 | soutzoe 16 | stenotype 17 | wubi 18 | wugniu 19 | ) 20 | -------------------------------------------------------------------------------- /preset-packages.bat: -------------------------------------------------------------------------------- 1 | set package_list=%package_list%^ 2 | bopomofo^ 3 | cangjie^ 4 | essay^ 5 | luna-pinyin^ 6 | prelude^ 7 | stroke^ 8 | terra-pinyin^ 9 | -------------------------------------------------------------------------------- /preset-packages.conf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | package_list+=( 4 | bopomofo 5 | cangjie 6 | essay 7 | luna-pinyin 8 | prelude 9 | stroke 10 | terra-pinyin 11 | ) 12 | -------------------------------------------------------------------------------- /rime-install: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ -z "${plum_repo}" ]]; then 4 | plum_repo='rime/plum' 5 | fi 6 | 7 | if [[ -z "${plum_dir}" ]]; then 8 | # am I in a working copy already? 9 | plum_dir="$(dirname "$(readlink -f "$0")")" 10 | if ! [[ -f "${plum_dir}"/scripts/install-packages.sh ]]; then 11 | # make a copy of plum in a subdirectory 12 | plum_dir='plum' 13 | fi 14 | fi 15 | 16 | if ! [[ -e "${plum_dir}" ]]; then 17 | git clone --depth 1 "https://github.com/${plum_repo}.git" "${plum_dir}" 18 | fi 19 | 20 | if ! [[ "$0" -ef "${plum_dir}"/rime-install ]]; then 21 | # run the newer version of rime-install 22 | "${plum_dir}"/rime-install "$@" 23 | exit 24 | fi 25 | 26 | export root_dir="${plum_dir}" 27 | source "${root_dir}"/scripts/bootstrap.sh 28 | require 'styles' 29 | 30 | if [[ -z "${rime_dir}" ]]; then 31 | # Output to Rime user directory 32 | require 'frontend' 33 | guess_rime_user_dir # exports `rime_dir` 34 | fi 35 | 36 | if [[ "$1" == '--select' ]]; then 37 | shift 38 | interactive=1 39 | fi 40 | 41 | if [[ $# -eq 0 ]]; then 42 | targets=(':preset') 43 | else 44 | targets=("$@") 45 | fi 46 | 47 | if [[ -n "${interactive}" ]]; then 48 | require 'selector' 49 | select_packages "${targets[@]}" 50 | targets=("${selected_packages[@]}") 51 | fi 52 | 53 | for target in "${targets[@]}"; do 54 | if [[ "${target}" == 'plum' ]]; then 55 | echo $(print_result 'Updating plum at') "'${plum_dir}'" 56 | (cd "${plum_dir}"; git pull) 57 | continue 58 | fi 59 | 60 | "${root_dir}"/scripts/install-packages.sh "${target}" "${rime_dir:-.}" 61 | done 62 | -------------------------------------------------------------------------------- /rime-install-bootstrap.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | setlocal 4 | 5 | set root_dir=%~dp0 6 | set PATH=%root_dir%;%PATH% 7 | 8 | set script_path=%root_dir%rime-install.bat 9 | set config_path=%root_dir%rime-install-config.bat 10 | 11 | rem download rime-install.bat if missing 12 | if exist "%script_path%" goto end_download 13 | 14 | where /q curl 15 | if %errorlevel% equ 0 ( 16 | set downloader=curl -fsSL 17 | set save_to=-o 18 | goto downloader_found 19 | ) 20 | 21 | where /q powershell 22 | if %errorlevel% equ 0 ( 23 | set downloader=powershell Invoke-WebRequest 24 | set save_to=-OutFile 25 | goto downloader_found 26 | ) 27 | 28 | echo Error: downloader not found. 29 | exit /b 1 30 | :downloader_found 31 | 32 | set script_url=https://raw.githubusercontent.com/rime/plum/master/rime-install.bat 33 | set config_url=https://github.com/rime/plum/raw/master/rime-install-config.bat 34 | 35 | echo Downloading rime-install.bat ... 36 | %downloader% "%script_url%" %save_to% "%script_path%" 37 | if errorlevel 1 ( 38 | echo Error downloading rime-install.bat 39 | exit /b 1 40 | ) 41 | 42 | if exist "%config_path%" goto end_download 43 | 44 | echo Downloading rime-install-config.bat template ... 45 | %downloader% "%config_url%" %save_to% "%config_path%" 46 | if errorlevel 1 ( 47 | echo Error downloading rime-install-config.bat 48 | exit /b 1 49 | ) 50 | 51 | :end_download 52 | 53 | set link_name=Rime package installer 54 | 55 | rem create shortcut 56 | powershell "$s=(New-Object -COM WScript.Shell).CreateShortcut('%root_dir%%link_name%.lnk');$s.TargetPath='\"%ComSpec%\"';$s.Arguments='/k \"%script_path%\"';$s.WorkingDirectory='%root_dir%';$s.Save()" 57 | -------------------------------------------------------------------------------- /rime-install-config.bat: -------------------------------------------------------------------------------- 1 | rem Location of download cache 2 | rem set download_cache_dir=%TEMP% 3 | 4 | rem Do not update packages; only download missing files. 5 | rem CAUTION: may suffer from incomplete downloads. 6 | rem set no_update=1 7 | 8 | rem Location of Rime configuration manager and downloaded packages 9 | rem set plum_dir=%APPDATA%\plum 10 | 11 | rem Location of Rime user directory 12 | rem set rime_dir=%APPDATA%\Rime 13 | 14 | set key=HKEY_CURRENT_USER\SOFTWARE\Rime\Weasel 15 | set name=RimeUserDir 16 | for /f "tokens=2*" %%a in ('reg query "%key%" /v "%name%"') do set rime_dir=%%b 17 | 18 | rem Disable /plum/ bash script; use batch installer only. 19 | rem set use_plum=0 20 | -------------------------------------------------------------------------------- /rime-install.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | setlocal enabledelayedexpansion 4 | 5 | title Rime package installer 6 | 7 | set root_dir=%~dp0 8 | set PATH=%root_dir%;%PATH% 9 | 10 | set config_file=%~dp0\rime-install-config.bat 11 | if exist "%config_file%" call "%config_file%" 12 | 13 | if not defined rime_dir set rime_dir=%APPDATA%\Rime 14 | if not defined download_cache_dir set download_cache_dir=%TEMP% 15 | if not exist "%download_cache_dir%" mkdir "%download_cache_dir%" 16 | 17 | echo. 18 | echo Rime package installer 19 | echo. 20 | echo Working directory: %CD% 21 | echo Package installer directory: %root_dir% 22 | echo Download cache directory: %download_cache_dir% 23 | echo Rime user directory: %rime_dir% 24 | echo. 25 | 26 | if defined ProgramFiles(x86) (set arch=64) else (set arch=32) 27 | 28 | call :find_7z 29 | call :find_git_bash 30 | call :find_downloader 31 | 32 | if not defined use_plum if "%has_git_bash%" == "1" set use_plum=1 33 | 34 | :process_arguments 35 | if "%1" == "" set batch_interactive=1 36 | 37 | if "%1" == "--select" if "%use_plum" == "1" ( 38 | call :install_with_plum %* 39 | exit /b !errorlevel! 40 | ) 41 | 42 | set /a installed_packages=0 43 | 44 | :next 45 | if "%batch_interactive%" == "1" ( 46 | set package= 47 | echo. && (set /p package=Enter package name, URL, user/repo or downloaded ZIP to install: ) 48 | ) else ( 49 | set package=%1 50 | shift 51 | ) 52 | if "%package%" == "" goto finish 53 | 54 | call :install_package 55 | if errorlevel 1 exit /b %errorlevel% 56 | goto next 57 | 58 | :install_package 59 | if "%package%" == "7z" ( 60 | call :install_7z 61 | exit /b %errorlevel% 62 | ) else if "%package%" == "git" ( 63 | call :install_git 64 | exit /b %errorlevel% 65 | ) else if "%package%" == "plum" ( 66 | call :install_with_plum plum 67 | exit /b %errorlevel% 68 | ) else if "%package:.zip=%.zip" == "%package%" ( 69 | if "https://github.com/%package:https://github.com/=%" == "%package%" ( 70 | set user_repo_path=%package:https://github.com/=% 71 | set archive_name=%package:*/archive/=% 72 | for /f "tokens=1 usebackq delims=." %%g in ('!archive_name!') do set branch=%%g 73 | call set package_repo=%%user_repo_path:/archive/!archive_name!=%% 74 | call :download_package 75 | ) else ( 76 | set package_file=%package% 77 | call :install_zip_package 78 | ) 79 | goto :after_install_package 80 | ) 81 | 82 | :prefer_plum_installer 83 | if "%use_plum%" == "1" ( 84 | call :install_with_plum %package% 85 | goto after_install_package 86 | ) 87 | :fallback_to_builtin_installer 88 | set branch= 89 | if "https://github.com/%package:https://github.com/=%" == "%package%" ( 90 | set user_repo_path=%package:https://github.com/=% 91 | if not "%package:/tree/=%" == "%package%" ( 92 | set branch=%package:*/tree/=% 93 | ) 94 | if defined branch ( 95 | call set package_repo=%%user_repo_path:/tree/!branch!=%% 96 | ) else ( 97 | set package_repo=!user_repo_path! 98 | ) 99 | call :download_package 100 | ) else if "%package:-packages.bat=%-packages.bat" == "%package%" ( 101 | call "%package%" 102 | call :install_package_group 103 | ) else if ":%package::=%" == "%package%" ( 104 | call "%package::=%-packages.bat" 105 | call :install_package_group 106 | ) else if not "%package:/=%" == "%package%" ( 107 | for /f "tokens=1,2 usebackq delims=@" %%g in ('%package%') do ( 108 | set package_repo=%%g 109 | set branch=%%h 110 | ) 111 | call :download_package 112 | ) else ( 113 | for /f "tokens=1,2 usebackq delims=@" %%g in ('%package%') do ( 114 | set user_repo_path=%%g 115 | set branch=%%h 116 | ) 117 | set package_repo=rime/rime-!user_repo_path:rime-=! 118 | call :download_package 119 | ) 120 | :after_install_package 121 | if not errorlevel 1 set /a installed_packages+=1 122 | exit /b %errorlevel% 123 | 124 | :download_package 125 | if not defined downloader ( 126 | set error_message=Downloader not found. 127 | goto error 128 | ) 129 | call :install_7z /needed 130 | if errorlevel 1 exit /b %errorlevel% 131 | if not defined branch ( 132 | for /f "tokens=2 usebackq delims=:, " %%g in (` 133 | %downloader% https://api.github.com/repos/%package_repo% ^| findstr default_branch 134 | `) do set branch=%%~g 135 | ) 136 | set package_url=https://github.com/%package_repo%/archive/%branch%.zip 137 | echo. 138 | echo Downloading %package_url% ... 139 | echo. 140 | set package_file=%download_cache_dir%\%package_repo:*/=%-%branch%.zip 141 | if "%no_update%" == "1" if exist "%package_file%" goto skip_download_package 142 | %downloader% "%package_url%" %save_to% "%package_file%" 143 | if errorlevel 1 ( 144 | set error_message=Error downloading %package_url% 145 | goto error 146 | ) 147 | :skip_download_package 148 | call :install_zip_package 149 | exit /b %errorlevel% 150 | 151 | :install_zip_package 152 | call :install_7z /needed 153 | if errorlevel 1 exit /b %errorlevel% 154 | echo. 155 | echo Unpacking %package_file% ... 156 | echo. 157 | for %%f in (%package_file%) do set package_dir=%%~nf 158 | set unpack_package_dir=%TEMP%\%package_dir% 159 | rem clean up obsolete files in target directory 160 | if exist "%unpack_package_dir%" rmdir /s /q "%unpack_package_dir%" 161 | rem unzip package 162 | 7z x "%package_file%" -o"%TEMP%" -y 163 | if errorlevel 1 ( 164 | set error_message=Error unpacking package %package_file% 165 | goto error 166 | ) 167 | if not exist "%rime_dir%" ( 168 | mkdir "%rime_dir%" 169 | if errorlevel 1 ( 170 | set error_message=Error creating rime user directory: %rime_dir% 171 | goto error 172 | ) 173 | ) 174 | rem install files from the unzipped package 175 | pushd "%unpack_package_dir%" 176 | for %%f in ( 177 | *.yaml 178 | *.txt 179 | opencc\*.json 180 | opencc\*.ocd 181 | opencc\*.txt 182 | ) do ( 183 | echo. 184 | echo Installing %%f ... 185 | echo. 186 | set target_file=%rime_dir%\%%f 187 | for %%t in (!target_file!) do set target_dir=%%~dpt 188 | if not exist "!target_dir!" mkdir "!target_dir!" 189 | copy /y "%%f" "!target_file!" 190 | if errorlevel 1 ( 191 | popd 192 | set error_message=Error installing files from package %package% 193 | goto error 194 | ) 195 | ) 196 | popd 197 | exit /b 198 | 199 | :install_package_group 200 | if not defined package_list ( 201 | set error_message=package_list is undefined in %package% 202 | goto error 203 | ) 204 | for %%p in (%package_list%) do ( 205 | set package=%%p 206 | call :install_package 207 | if errorlevel 1 exit /b !errorlevel! 208 | ) 209 | exit /b 210 | 211 | :install_with_plum 212 | call :install_git /needed 213 | if errorlevel 1 exit /b %errorlevel% 214 | 215 | set WSLENV=plum_dir:rime_dir 216 | 217 | if defined plum_dir if exist "%plum_dir%"/rime-install ( 218 | bash "%plum_dir%"/rime-install %* 219 | exit /b !errorlevel! 220 | ) 221 | if exist plum/rime-install ( 222 | bash plum/rime-install %* 223 | ) else if exist rime-install ( 224 | bash rime-install %* 225 | ) else ( 226 | echo Downloading rime-install ... 227 | set script_url=https://raw.githubusercontent.com/rime/plum/master/rime-install 228 | curl -fsSL "!script_url!" -o "%download_cache_dir%"/rime-install 229 | if errorlevel 1 ( 230 | set error_message=Error downloading rime-install 231 | goto error 232 | ) 233 | bash "%download_cache_dir%"/rime-install %* 234 | ) 235 | exit /b %errorlevel% 236 | 237 | :install_7z 238 | where /q 7z 239 | if not errorlevel 1 ( 240 | if "%1" == "/needed" exit /b 241 | echo. 242 | echo Found 7z 243 | echo. 244 | exit /b 245 | ) 246 | 247 | rem check for updates at https://www.7-zip.org/download.html 248 | if not defined _7z_version set _7z_version=18.01 249 | 250 | if "%arch%" == "64" (set _7z_arch=-x%arch%) else (set _7z_arch=) 251 | set _7z_installer=7z%_7z_version:.=%%_7z_arch%.exe 252 | 253 | rem find local 7z installer 254 | where /q %_7z_installer% 255 | if not errorlevel 1 ( 256 | echo. 257 | echo Found installer: %_7z_installer% 258 | echo. 259 | set _7z_installer_path=%_7z_installer% 260 | goto run_7z_installer 261 | ) 262 | 263 | set _7z_installer_path=%download_cache_dir%\%_7z_installer% 264 | if "%no_update%" == "1" if exist "%_7z_installer_path%" goto run_7z_installer 265 | 266 | :download_7z_installer 267 | set _7z_download_url=https://www.7-zip.org/a/%_7z_installer% 268 | if not defined downloader ( 269 | echo. 270 | echo TODO: please download and install 7z: %_7z_download_url% 271 | echo. 272 | set error_message=Downloader not found. 273 | goto error 274 | ) 275 | echo. 276 | echo Downloading installer: %_7z_installer% 277 | echo. 278 | %downloader% "%_7z_download_url%" %save_to% "%_7z_installer_path%" 279 | if errorlevel 1 ( 280 | set error_message=Error downloading %_7z_installer% 281 | goto error 282 | ) 283 | rem TODO: verify installer 284 | echo. 285 | echo Download complete: %_7z_installer% 286 | echo. 287 | 288 | :run_7z_installer 289 | echo. 290 | echo Installing 7z ... 291 | echo. 292 | "%_7z_installer_path%" /S 293 | 294 | exit /b 295 | 296 | :install_git 297 | where /q git 298 | if not errorlevel 1 ( 299 | if "%1" == "/needed" exit /b 300 | echo. 301 | echo Found git 302 | echo. 303 | exit /b 304 | ) 305 | 306 | rem check for updates at https://github.com/git-for-windows/git/releases/latest 307 | if not defined git_version set git_version=2.17.0 308 | if not defined git_release set git_release=.1 309 | 310 | set git_installer=Git-%git_version%%git_release:.1=%-%arch%-bit.exe 311 | rem find local Git installer 312 | where /q %git_installer% 313 | if not errorlevel 1 ( 314 | echo. 315 | echo Found installer: %git_installer% 316 | echo. 317 | set git_installer_path=%git_installer% 318 | goto run_git_installer 319 | ) 320 | 321 | set git_installer_path=%download_cache_dir%\%git_installer% 322 | if "%no_update%" == "1" if exist "%git_installer_path%" goto run_git_installer 323 | 324 | :download_git_installer 325 | set git_download_url_prefix=https://github.com/git-for-windows/git/releases/download/ 326 | set git_download_url=%git_download_url_prefix%v%git_version%.windows%git_release%/%git_installer% 327 | 328 | if not defined downloader ( 329 | echo. 330 | echo TODO: please download and install git: %git_download_url% 331 | echo. 332 | set error_message=Downloader not found. 333 | goto error 334 | ) 335 | echo. 336 | echo Downloading installer: %git_installer% 337 | echo. 338 | %downloader% "%git_download_url%" %save_to% "%git_installer_path%" 339 | if errorlevel 1 ( 340 | set error_message=Error downloading %git_installer% 341 | goto error 342 | ) 343 | rem TODO: verify installer 344 | echo. 345 | echo Download complete: %git_installer% 346 | echo. 347 | 348 | :run_git_installer 349 | echo. 350 | echo Installing git ... 351 | echo. 352 | "%git_installer_path%" /SILENT 353 | 354 | exit /b 355 | 356 | :find_7z 357 | set search_path=^ 358 | %ProgramFiles%\7-Zip; 359 | 360 | if defined ProgramW6432 set search_path=%search_path%^ 361 | %ProgramW6432%\7-Zip; 362 | 363 | if defined ProgramFiles(x86) set search_path=%search_path%^ 364 | %ProgramFiles(x86)%\7-Zip; 365 | 366 | set PATH=%search_path%%PATH% 367 | 368 | where /q 7z 369 | if %errorlevel% equ 0 set has_7z=1 370 | exit /b 371 | 372 | :find_git_bash 373 | set search_path=^ 374 | %ProgramFiles%\Git\cmd;^ 375 | %ProgramFiles%\Git\mingw%arch%\bin;^ 376 | %ProgramFiles%\Git\usr\bin; 377 | 378 | rem find 64-bit Git in 32-bit cmd.exe 379 | if defined ProgramW6432 set search_path=%search_path%^ 380 | %ProgramW6432%\Git\cmd;^ 381 | %ProgramW6432%\Git\mingw%arch%\bin;^ 382 | %ProgramW6432%\Git\usr\bin; 383 | 384 | rem find user installed 32-bit Git on 64-bit OS 385 | if defined ProgramFiles(x86) set search_path=%search_path%^ 386 | %ProgramFiles(x86)%\Git\cmd;^ 387 | %ProgramFiles(x86)%\Git\mingw32\bin;^ 388 | %ProgramFiles(x86)%\Git\usr\bin; 389 | 390 | set PATH=%search_path%%PATH% 391 | 392 | where /q git 393 | if %errorlevel% equ 0 set has_git=1 394 | 395 | where /q bash 396 | if %errorlevel% equ 0 set has_bash=1 397 | 398 | if "%has_git%" == "1" if "%has_bash%" == "1" set has_git_bash=1 399 | exit /b 400 | 401 | :find_downloader 402 | where /q curl 403 | if %errorlevel% equ 0 ( 404 | set downloader=curl -fsSL 405 | set save_to=-o 406 | goto downloader_found 407 | ) 408 | 409 | where /q powershell 410 | if %errorlevel% equ 0 ( 411 | set downloader=powershell Invoke-WebRequest 412 | set save_to=-OutFile 413 | goto downloader_found 414 | ) 415 | :downloader_found 416 | exit /b 417 | 418 | :error 419 | echo. 420 | echo Installation failed: %error_message% 421 | echo. 422 | exit /b 1 423 | 424 | :finish 425 | echo. 426 | if %installed_packages% equ 0 ( 427 | echo No package installed. 428 | ) else ( 429 | echo Installed %installed_packages% packages. 430 | ) 431 | echo. 432 | 433 | :exit 434 | -------------------------------------------------------------------------------- /scripts/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # bootstraps the script module system 4 | # 5 | # usage: 6 | # - source this file in the main script 7 | # - require 'module-name' 8 | # in modules: 9 | # - require module dependencies 10 | # - define module 11 | # - provide 'module-name' 12 | 13 | module_root_dir="$(dirname "${BASH_SOURCE[0]}")" 14 | 15 | provide() { 16 | local module_name="$1" 17 | loaded_modules+=("${module_name}") 18 | } 19 | 20 | require() { 21 | local module_name="$1" 22 | if grep -qF " ${module_name} " <<<" ${loaded_modules[*]} "; then return; fi 23 | source "${module_root_dir}/${module_name}.sh" 24 | if grep -qF " ${module_name} " <<<" ${loaded_modules[*]} "; then return; fi 25 | echo >&2 "ERROR: failed to load module '${module_name}'" 26 | } 27 | 28 | provide 'bootstrap' 29 | -------------------------------------------------------------------------------- /scripts/fetch-package.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Fetch a Rime data package from GitHub 4 | # 5 | 6 | package_name="$1" 7 | shift 8 | 9 | if [[ -z "${package_name}" ]]; then 10 | echo "Usage: $(basename "$0") [] [-b ]" 11 | exit 1 12 | fi 13 | 14 | resolve_package_name() { 15 | local name="$1" 16 | if [[ ${name} =~ [^/]*/[^/]* ]]; then 17 | echo ${name} 18 | elif [[ ${name} =~ rime-[^/]* ]]; then 19 | echo rime/${name} 20 | else 21 | echo rime/rime-${name} 22 | fi 23 | } 24 | 25 | package_url="https://github.com/$(resolve_package_name "${package_name}").git" 26 | 27 | git_version_greater_or_equal() { 28 | local target_major="$1" 29 | local target_minor="$2" 30 | local git_version_pattern='^git version ([0-9]*)\.([0-9]*).*$' 31 | if [[ "$(git --version | grep '^git version')" =~ $git_version_pattern ]]; then 32 | local major="${BASH_REMATCH[1]}" 33 | local minor="${BASH_REMATCH[2]}" 34 | [[ "${major}" -gt "${target_major}" ]] || ( 35 | [[ "${major}" -eq "${target_major}" ]] && [[ "${minor}" -ge "${target_minor}" ]] 36 | ) 37 | else 38 | return 1 39 | fi 40 | } 41 | 42 | clone_options=( 43 | --depth 1 44 | --recurse-submodules 45 | ) 46 | 47 | if git_version_greater_or_equal 2 9; then 48 | clone_options+=( 49 | --shallow-submodules 50 | ) 51 | fi 52 | 53 | git clone ${clone_options[@]} "${package_url}" "$@" 54 | -------------------------------------------------------------------------------- /scripts/frontend.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | require 'styles' 4 | 5 | guess_rime_user_dir() { 6 | if [[ -n "${rime_dir}" ]]; then 7 | return 8 | fi 9 | if [[ -z "${rime_frontend}" ]]; then 10 | # guess frontend by OS 11 | case "$OSTYPE" in 12 | linux*) 13 | export rime_frontend='rime/ibus-rime' 14 | ;; 15 | darwin*) 16 | export rime_frontend='rime/squirrel' 17 | ;; 18 | cygwin* | msys* | win*) 19 | # Weasel 20 | export rime_frontend='rime/weasel' 21 | ;; 22 | *) 23 | echo $(warning 'WARNING:') 'Unknown OSTYPE:' $(print_option "$OSTYPE") 24 | ;; 25 | esac 26 | fi 27 | # install to default rime user directory 28 | case "${rime_frontend}" in 29 | fcitx/fcitx-rime | fcitx-rime) 30 | export rime_dir="$HOME/.config/fcitx/rime" 31 | ;; 32 | fcitx5/fcitx5-rime | fcitx5-rime) 33 | export rime_dir="$HOME/.local/share/fcitx5/rime" 34 | ;; 35 | rime/ibus-rime | ibus-rime) 36 | export rime_dir="$HOME/.config/ibus/rime" 37 | ;; 38 | rime/squirrel | squirrel) 39 | export rime_dir="$HOME/Library/Rime" 40 | ;; 41 | rime/weasel | weasel) 42 | export rime_dir="$APPDATA\\Rime" 43 | ;; 44 | *) 45 | echo $(warning 'WARNING:') 'Unknown Rime frontend:' $(print_option "${rime_frontend:-(unknown)}") 46 | return 47 | ;; 48 | esac 49 | echo 'Installing for Rime frontend:' $(print_option "${rime_frontend:-(unknown)}") 50 | } 51 | 52 | provide 'frontend' 53 | -------------------------------------------------------------------------------- /scripts/install-packages.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | script_dir="$(dirname "$0")" 4 | target="$1" 5 | output_dir="$2" 6 | 7 | option_no_update="${no_update:+1}" 8 | 9 | source "${script_dir}"/bootstrap.sh 10 | require 'styles' 11 | require 'resolver' 12 | 13 | if [[ -z "$target" ]] || [[ -z "$output_dir" ]]; then 14 | echo "Usage: $(basename "$0") :| " 15 | exit 1 16 | fi 17 | 18 | set -e 19 | 20 | [[ -d "${output_dir}" ]] || mkdir -p "${output_dir}" 21 | 22 | files_updated=0 23 | 24 | install_package() { 25 | local user_name="$(resolve_user_name "$1")" 26 | local package_name="$(resolve_package_name "$1")" 27 | local package_dir="${root_dir:-.}/package/${user_name}/${package_name}" 28 | 29 | local package="$(resolve_package "$1")" 30 | local branch="$(resolve_branch "$1")" 31 | local branch_label="${branch:+@${branch}}" 32 | 33 | local recipe="$(resolve_recipe "$1")" 34 | local recipe_options=($(resolve_recipe_options "$1")) 35 | 36 | fetch_or_update_package 37 | 38 | if [[ -n "${recipe}" ]]; then 39 | require 'recipe' 40 | install_recipe "${package_dir}/${recipe}.recipe.yaml" 41 | elif [[ -f "${package_dir}/recipe.yaml" ]]; then 42 | require 'recipe' 43 | install_recipe "${package_dir}/recipe.yaml" 44 | else 45 | install_files_from_package "${package_dir}" 46 | fi 47 | } 48 | 49 | fetch_or_update_package() { 50 | if ! [[ -d "${package_dir}" ]]; then 51 | echo $(info 'Downloading package:') $(highlight "${package}") $(print_option "${branch_label}") 52 | local fetch_options=() 53 | if [[ -n "${branch}" ]]; then 54 | fetch_options+=(--branch "${branch}") 55 | fi 56 | "${script_dir}"/fetch-package.sh "${package}" "${package_dir}" "${fetch_options[@]}" 57 | else 58 | if [[ -z "${option_no_update}" ]]; then 59 | echo $(info 'Updating package:') $(highlight "${package}") 60 | else 61 | echo $(info 'Found package:') $(highlight "${package}") 62 | fi 63 | "${script_dir}"/update-package.sh "${package_dir}" "${branch}" 64 | fi 65 | } 66 | 67 | install_files_from_package() { 68 | local package_dir="$1" 69 | local IFS=$'\r\n' 70 | local data_files=( 71 | $( 72 | cd "${package_dir}" 73 | ls *.yaml 2> /dev/null \ 74 | | grep -v -e '\.custom\.yaml$' -e '\.recipe\.yaml$' -e '^recipe\.yaml$' 75 | ls *.txt 2> /dev/null 76 | ls *.gram 2> /dev/null 77 | ls opencc/*.* 2> /dev/null \ 78 | | grep -e '\.json$' -e '\.ocd$' -e '\.txt$' 79 | ) 80 | ) 81 | install_files "${data_files[@]}" 82 | } 83 | 84 | install_files() { 85 | if [[ "$#" -eq 0 ]]; then 86 | return 87 | fi 88 | local source_path 89 | local target_path 90 | for file in "$@"; do 91 | source_path="${package_dir}/${file}" 92 | target_path="${output_dir}/${file}" 93 | if ! [ -e "${target_path}" ]; then 94 | create_containing_directory "${target_path}" 95 | echo $(info 'Installing:') $(print_item "${file}") 96 | elif ! diff -q "${source_path}" "${target_path}" &> /dev/null; then 97 | echo $(info 'Updating:') $(print_item "${file}") 98 | else 99 | continue 100 | fi 101 | cp "${source_path}" "${target_path}" 102 | ((++files_updated)) 103 | done 104 | } 105 | 106 | create_containing_directory() { 107 | local target_dir="$(dirname "$1")" 108 | if ! [ -d "${target_dir}" ]; then 109 | echo $(info 'Creating directory:') $(print_item "${target_dir}") 110 | mkdir -p "${target_dir}" 111 | fi 112 | } 113 | 114 | load_package_list_from_target "${target}" 115 | 116 | for package in "${package_list[@]}"; do 117 | install_package "${package}" 118 | done 119 | 120 | if [[ "${files_updated}" -eq 0 ]]; then 121 | echo $(print_result 'No files updated.') 122 | else 123 | echo $(print_result "Updated ~ ${files_updated} files " \ 124 | "from ${#package_list[@]} packages in") "'${output_dir}'" 125 | fi 126 | -------------------------------------------------------------------------------- /scripts/minimal-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # encoding: utf-8 3 | 4 | script_dir="$(dirname "$0")" 5 | output_dir="$1" 6 | 7 | for package in essay luna-pinyin prelude; do 8 | bash "${script_dir}"/install-packages.sh "${package}" "${output_dir}" 9 | done 10 | 11 | pushd "${output_dir}" > /dev/null 12 | 13 | awk '($2 >= 500) {print}' essay.txt > essay.txt.min 14 | mv essay.txt.min essay.txt 15 | 16 | sed -n '{ 17 | s/^version: \(["]*\)\([0-9.]*\)\(["]*\)$/version: \1\2.minimal\3/ 18 | /^#以下爲詞組$/q;p 19 | }' luna_pinyin.dict.yaml > luna_pinyin.dict.yaml.min 20 | mv luna_pinyin.dict.yaml.min luna_pinyin.dict.yaml 21 | 22 | for schema in *.schema.yaml; do 23 | sed '{ 24 | s/version: \(["]*\)\([0-9.]*\)\(["]*\)$/version: \1\2.minimal\3/ 25 | s/\(- stroke\)$/#\1/ 26 | s/\(- reverse_lookup_translator\)$/#\1/ 27 | }' ${schema} > ${schema}.min 28 | mv ${schema}.min ${schema} 29 | done 30 | 31 | ls *.schema.yaml | sed 's/^\(.*\)\.schema\.yaml/ - schema: \1/' > schema_list.yaml 32 | grep -Ff schema_list.yaml default.yaml > schema_list.yaml.min 33 | mv schema_list.yaml.min schema_list.yaml 34 | sed '{ 35 | s/^config_version: \(["]*\)\([0-9.]*\)\(["]*\)$/config_version: \1\2.minimal\3/ 36 | /- schema:/d 37 | /^schema_list:$/r schema_list.yaml 38 | }' default.yaml > default.yaml.min 39 | rm schema_list.yaml 40 | mv default.yaml.min default.yaml 41 | 42 | popd > /dev/null 43 | -------------------------------------------------------------------------------- /scripts/recipe.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | require 'styles' 4 | 5 | install_recipe() { 6 | local recipe_file="$1" 7 | if ! [[ -f "${recipe_file}" ]]; then 8 | echo $(error 'Recipe not found:') "${recipe_file}" 9 | exit 1 10 | fi 11 | 12 | local rx="${package}${recipe:+:${recipe}}" 13 | echo $(info 'Installing recipe:') $(highlight "${rx}") 14 | for option in "${recipe_options[@]}"; do 15 | echo $(info '- option:') $(print_option "${option}") 16 | done 17 | 18 | check_recipe_info 19 | 20 | apply_download_files 21 | 22 | apply_install_files 23 | 24 | apply_patch_files 25 | } 26 | 27 | print_section() { 28 | local section="$1" 29 | sed -n '/^'"${section}"':/,/^[^[:space:]#]/ { 30 | /^[^[:space:]#]/ !p 31 | }' 32 | } 33 | 34 | check_recipe_info() { 35 | local recipe_decl=$( 36 | cat "${recipe_file}" | 37 | print_section 'recipe' | 38 | grep '^[ ]*Rx: ' | 39 | sed 's/^[ ]*Rx:[ "'"'"']*\(.*\)[ "'"'"']*$/\1/' 40 | ) 41 | [[ -z "${recipe}" ]] || [[ "${recipe_decl}" == "${recipe}" ]] || ( 42 | echo $(error 'Invalid recipe:') "'${recipe_decl}' does not match file name '${recipe_file}'" 43 | exit 1 44 | ) 45 | } 46 | 47 | get_filename() { 48 | local url="$1" 49 | # if a filename is specified, use it 50 | if [[ "$url" = *::* ]]; then 51 | echo "${url%%::*}" 52 | else 53 | echo "${url##*/}" 54 | fi 55 | } 56 | 57 | download_file() { 58 | local url="$1" 59 | local filename="$(get_filename $url)" 60 | local check_update="" 61 | local msg='Downloading file:' 62 | 63 | if [[ -e "${package_dir}/${filename}" ]]; then 64 | check_update="-z $filename" 65 | msg='Checking for update of external file:' 66 | fi 67 | 68 | ( 69 | cd "${package_dir}" 70 | echo $(info "$msg") $(highlight "$filename") 71 | curl -fRL -o "$filename" $check_update "${url#*::}" 72 | ) 73 | } 74 | 75 | apply_download_files() { 76 | if ! grep -q '^download_files:' "${recipe_file}"; then 77 | return 78 | fi 79 | local file_patterns=( 80 | $(cat "${recipe_file}" | 81 | print_section 'download_files' | 82 | sed '/^[ ]*#/ d; s/^[ ]*-[ ]//' 83 | ) 84 | ) 85 | if (( ${#file_patterns[@]} == 0 )); then 86 | return 87 | fi 88 | for _item in ${file_patterns[@]}; do 89 | download_file $_item || ( 90 | echo $(error 'Error:') "failed to download files in recipe ${rx}" 91 | exit 1 92 | ) 93 | done 94 | } 95 | 96 | apply_install_files() { 97 | if ! grep -q '^install_files:' "${recipe_file}"; then 98 | return 99 | fi 100 | local file_patterns=( 101 | $(cat "${recipe_file}" | 102 | print_section 'install_files' | 103 | sed '/^[ ]*#/ d; s/^[ ]*-[ ]//' 104 | ) 105 | ) 106 | if (( ${#file_patterns[@]} == 0 )); then 107 | return 108 | fi 109 | install_files $( 110 | cd "${package_dir}" 111 | ls ${file_patterns[@]} || 112 | echo $(error 'Error: some files to install are not found.') >&2 113 | ) || ( 114 | echo $(error 'Error:') "failed to install files in recipe ${rx}" 115 | exit 1 116 | ) 117 | } 118 | 119 | apply_patch_files() { 120 | if ! grep -q '^patch_files:' "${recipe_file}"; then 121 | return 122 | fi 123 | local script_header="\ 124 | #!/usr/bin/env bash 125 | source '${script_dir}/bootstrap.sh' 126 | require 'recipe' 127 | output_dir='${output_dir}' 128 | package='${package}' 129 | recipe='${recipe}' 130 | recipe_options=( 131 | ${recipe_options[*]} 132 | ) 133 | eval \${recipe_options[@]} 134 | " 135 | cat "${recipe_file}" | 136 | print_section 'patch_files' | 137 | sed '{ 138 | 1 i\ 139 | '"$(escape_sed_text <<<"${script_header}")"' 140 | # patch files 141 | s/^[ ][ ]// 142 | s/^\([^[:space:]#]*\):\s*$/patch_file \1 <> "${target_file}" 165 | fi 166 | local option_list="${recipe_options[*]}" 167 | local rx="${package}:${recipe}:${option_list// /,}" 168 | if grep -Fq "# Rx: ${rx}" "${target_file}"; then 169 | echo $(info 'Updating patch.') 170 | # first remove the existing patch 171 | sed '/^# Rx: '"${rx//\//\\/}"' {$/,/^# }$/ d' \ 172 | "${target_file}" > "${target_file}.new" && 173 | mv "${target_file}.new" "${target_file}" 174 | fi 175 | # read patch contents from standard input 176 | local patch_contents="$(escape_sed_text)" 177 | sed -E ' 178 | /^__patch:$/,/^[^[:space:]#]/ { 179 | $ { 180 | /^__patch:|^[[:space:]#]/ { 181 | a\ 182 | # Rx: '"${rx}"' {\ 183 | '"${patch_contents}"' 184 | # } 185 | q 186 | } 187 | i\ 188 | # Rx: '"${rx}"' {\ 189 | '"${patch_contents}"' 190 | # } 191 | } 192 | } 193 | ' "${target_file}" > "${target_file}.new" && 194 | mv "${target_file}.new" "${target_file}" || ( 195 | echo $(error 'Error patching:') "${file_name}" 196 | exit 1 197 | ) 198 | } 199 | 200 | provide 'recipe' 201 | -------------------------------------------------------------------------------- /scripts/resolver.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | require 'styles' 4 | 5 | # a recipe order takes the form 6 | # /@::key=value,... 7 | # 8 | # the "/" and/or "@", ":..." parts can be omitted 9 | 10 | resolve_user_name() { 11 | local package="${1%%[@:]*}" 12 | local user_name='rime' 13 | if [[ "${package}" =~ / ]]; then 14 | user_name="${package%/*}" 15 | fi 16 | echo "${user_name}" 17 | } 18 | 19 | resolve_package_name() { 20 | local package="${1%%[@:]*}" 21 | local repo_name="${package##*/}" 22 | local package_name="${repo_name#rime-}" 23 | echo "${package_name}" 24 | } 25 | 26 | resolve_package() { 27 | local package="${1%%[@:]*}" 28 | echo "${package}" 29 | } 30 | 31 | # returns empty string if not specified 32 | resolve_branch() { 33 | local package="${1%%:*}" 34 | if [[ "${package}" =~ @ ]]; then 35 | echo "${package##*@}" 36 | fi 37 | } 38 | 39 | # returns empty string if not specified 40 | resolve_recipe() { 41 | local rx="$1" 42 | if [[ "${rx}" =~ : ]]; then 43 | rx="${rx#*:}" 44 | echo "${rx%%:*}" 45 | fi 46 | } 47 | 48 | resolve_recipe_options() { 49 | local rx="$1" 50 | if [[ "${rx}" =~ : ]]; then 51 | rx="${rx#*:}" 52 | if [[ "${rx}" =~ : ]]; then 53 | echo "${rx#*:}" | sed 's/[:,]/ /g' 54 | fi 55 | fi 56 | } 57 | 58 | expand_configuration_url() { 59 | if [[ "$1" =~ ^https:// ]]; then 60 | echo "$1" 61 | elif [[ "$1" =~ ^([^/@:]*)/([^/@:]*)(@[^/@:]*)?/([^@:]*-packages.conf)$ ]]; then 62 | local user="${BASH_REMATCH[1]}" 63 | local repo="${BASH_REMATCH[2]}" 64 | local branch="${BASH_REMATCH[3]#@}" 65 | local filepath="${BASH_REMATCH[4]}" 66 | echo "https://github.com/${user}/${repo}/raw/${branch:-master}/${filepath}" 67 | fi 68 | } 69 | 70 | load_package_list_from_target() { 71 | local target="$1" 72 | case "${target}" in 73 | */*/*-packages.conf |\ 74 | https://github.com/*/raw/*-packages.conf |\ 75 | https://raw.githubusercontent.com/*-packages.conf) 76 | local configuration_url="$(expand_configuration_url "${target}")" 77 | if [[ -z "${configuration_url}" ]]; then 78 | echo $(error 'ERROR:') "unable to recognize configuration: ${target}" >&2 79 | exit 1 80 | fi 81 | echo $(info 'Fetching') "${configuration_url}" 82 | curl -fLO "${configuration_url}" 83 | source "$(basename "${configuration_url}")" 84 | ;; 85 | *.conf) 86 | source "${target}" 87 | ;; 88 | :*) 89 | source "${root_dir:-.}/${target#:}"-packages.conf 90 | ;; 91 | *) 92 | package_list=("${target}") 93 | ;; 94 | esac 95 | } 96 | 97 | provide 'resolver' 98 | -------------------------------------------------------------------------------- /scripts/selector.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | require 'styles' 4 | require 'resolver' 5 | 6 | select_packages() { 7 | local all_packages=() 8 | local target 9 | local package 10 | for target in "$@"; do 11 | load_package_list_from_target "${target}" 12 | for package in "${package_list[@]}"; do 13 | if ! (echo " ${all_packages[*]} " | grep -qF " ${package} "); then 14 | all_packages+=("${package}") 15 | fi 16 | done 17 | done 18 | 19 | selected_packages=() 20 | local PS3="$(prompt '#') Enter number, package name or '.' when finished $(prompt '#') " 21 | echo $(highlight 'Select packages to install:') 22 | select selected in "${all_packages[@]}"; do 23 | if [[ -n "${selected}" ]]; then 24 | selected_packages+=("${selected}") 25 | else 26 | case "$REPLY" in 27 | end | ok | 0 | .) 28 | break 29 | ;; 30 | cancel | exit | quit) 31 | echo $(warning 'Installation canceled.') 32 | exit 33 | ;; 34 | reset | clear) 35 | selected_packages=() 36 | echo $(print_result 'Reset selected packages.') 37 | continue 38 | ;; 39 | [:A-Za-z]*) 40 | selected_packages+=("$REPLY") 41 | ;; 42 | *) 43 | echo $(error 'ERROR:') 'invalid number or package name:' $(print_option "$REPLY") 44 | continue 45 | ;; 46 | esac 47 | fi 48 | echo "You will rime with $(print_item ${selected_packages[@]}) (+$(print_option $REPLY))" 49 | done 50 | 51 | if [[ ${#selected_packages} -eq 0 ]]; then 52 | echo $(warning 'You did not select any packages.') 53 | echo 54 | echo -n "$(highlight 'Do you want to install default packages?') ($(print_item $@))" 55 | read -p " $(prompt '[Y/n]') " answer 56 | case "${answer}" in 57 | '' | y*) 58 | selected_packages=("$@") 59 | ;; 60 | *) 61 | echo $(warning 'Installation canceled.') 62 | exit 63 | ;; 64 | esac 65 | fi 66 | } 67 | 68 | provide 'selector' 69 | -------------------------------------------------------------------------------- /scripts/split-packages.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | old_branch=master 4 | new_branch=split-packages 5 | 6 | package_files() { 7 | local package="$1" 8 | grep "^${package}=" < []" 14 | exit 1 15 | fi 16 | 17 | git_current_branch() { 18 | if ! command git rev-parse 2> /dev/null 19 | then 20 | # not a git repository 21 | return 2 22 | fi 23 | local ref="$(command git symbolic-ref HEAD 2> /dev/null)" 24 | if [[ -n "$ref" ]] 25 | then 26 | echo "${ref#refs/heads/}" 27 | return 0 28 | else 29 | return 1 30 | fi 31 | } 32 | 33 | git_default_branch() { 34 | if ! command git rev-parse 2> /dev/null 35 | then 36 | return 2 37 | fi 38 | local ref="$(command git symbolic-ref refs/remotes/origin/HEAD 2> /dev/null)" 39 | if [[ -n "$ref" ]] 40 | then 41 | echo "${ref#refs/remotes/origin/}" 42 | return 0 43 | else 44 | return 1 45 | fi 46 | } 47 | 48 | fetch_all_branches() { 49 | local fetch_all_pattern='\+refs/heads/\*:' 50 | if ! [[ "$(git config --get remote.origin.fetch)" =~ $fetch_all_pattern ]]; then 51 | if [[ -n "${option_no_update}" ]]; then 52 | echo $(warning 'WARNING:') 'forced update for switching branch to' $(print_option "${target_branch}") 53 | fi 54 | git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*' 55 | elif [[ -n "${option_no_update}" ]]; then 56 | return 57 | fi 58 | git fetch origin --depth 1 59 | } 60 | 61 | switch_branch() { 62 | local target_branch="$1" 63 | if [[ -z "${branch}" ]]; then 64 | echo $(warning 'WARNING:') "'${package_dir}' was on" \ 65 | $(print_option "${current_branch:-(detached HEAD)}") 'instead of' $(print_option "${target_branch}") 66 | fi 67 | fetch_all_branches 68 | git checkout "${target_branch}" || exit 1 69 | } 70 | 71 | pushd "${package_dir}" &> /dev/null 72 | 73 | current_branch="$(git_current_branch)" 74 | if [[ $? -gt 1 ]]; then 75 | echo $(warning 'WARNING:') "not a git repository, skipped updating '${package_dir}'" 76 | exit 77 | fi 78 | if [[ -z "${branch}" ]]; then 79 | target_branch="$(git_default_branch)" 80 | else 81 | target_branch="${branch}" 82 | fi 83 | if [[ "${current_branch}" != "${target_branch}" ]]; then 84 | switch_branch "${target_branch}" 85 | elif [[ -z "${option_no_update}" ]]; then 86 | git fetch --recurse-submodules && ( 87 | git merge --ff-only "origin/${target_branch}" || ( 88 | echo $(warning 'WARNING:') 'fast-forward failed;' \ 89 | 'doing a hard reset to' $(print_option "origin/${target_branch}") 90 | git reset --hard "origin/${target_branch}" 91 | ) 92 | ) || exit 1 93 | fi 94 | 95 | popd &> /dev/null 96 | --------------------------------------------------------------------------------