├── web ├── CNAME ├── favicon.ico ├── style.css ├── index.html └── typeahead.bundle.min.js ├── ts_src ├── index.ts ├── tests.ts ├── replace.ts └── ui.ts ├── setup.cfg ├── docs ├── automator.png ├── unicodeit_demo.gif └── dev.md ├── unicodeit ├── cli.py ├── __init__.py ├── export_data.py └── replace.py ├── .eslintignore ├── .eslintrc.js ├── .pylintrc ├── tsconfig.json ├── tests ├── test_subsuper.py ├── test_data.py ├── test_cli.py └── test_v06symbols.py ├── webpack.config.js ├── .gitignore ├── setup.py ├── LICENSE ├── package.json ├── .github └── workflows │ ├── tests.yml │ └── deploy.yml ├── README.md └── LICENSE.LPPL /web/CNAME: -------------------------------------------------------------------------------- 1 | www.unicodeit.net 2 | -------------------------------------------------------------------------------- /ts_src/index.ts: -------------------------------------------------------------------------------- 1 | export { replace } from './replace'; 2 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [pycodestyle] 2 | max-line-length=119 3 | ignore=E741,W503 4 | -------------------------------------------------------------------------------- /web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atcold/unicodeit/master/web/favicon.ico -------------------------------------------------------------------------------- /docs/automator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atcold/unicodeit/master/docs/automator.png -------------------------------------------------------------------------------- /docs/unicodeit_demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atcold/unicodeit/master/docs/unicodeit_demo.gif -------------------------------------------------------------------------------- /unicodeit/cli.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from .replace import replace 4 | 5 | 6 | if __name__ == "__main__": 7 | result = [replace(f) for f in sys.argv[1:]] 8 | print(' '.join(result)) 9 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # don't ever lint node_modules 2 | node_modules 3 | # don't lint build output (make sure it's set to your correct build folder name) 4 | ts_dist 5 | # don't lint nyc coverage output 6 | coverage 7 | -------------------------------------------------------------------------------- /unicodeit/__init__.py: -------------------------------------------------------------------------------- 1 | """Converts LaTeX tags to unicode.""" 2 | 3 | from .replace import replace 4 | 5 | __author__ = 'Sven Kreiss , Kyle Cranmer ' 6 | __version__ = '0.7.2' 7 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | plugins: [ 5 | '@typescript-eslint', 6 | ], 7 | extends: [ 8 | 'eslint:recommended', 9 | 'plugin:@typescript-eslint/recommended', 10 | ], 11 | }; 12 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [BASIC] 2 | 3 | variable-rgx=[a-z0-9_]{1,30}$ 4 | good-names=ap,ar,ax,d,f,g,gt,h,i,im,lr,p,r,s,t,t1,t2,th,v,vs,w,wh,x,x1,x2,xs,y,ys,xy 5 | 6 | 7 | 8 | [TYPECHECK] 9 | 10 | disable=duplicate-code,missing-docstring,invalid-name,redefined-outer-name 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./ts_dist/js", 4 | "sourceMap": true, 5 | "declaration": true, 6 | "noImplicitAny": true, 7 | "module": "commonjs", 8 | "target": "es6", 9 | "jsx": "react", 10 | "allowJs": true 11 | }, 12 | "include": [ 13 | "ts_src/**/*" 14 | ], 15 | "exclude": [ 16 | "node_modules/", 17 | "ts_dist" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /tests/test_subsuper.py: -------------------------------------------------------------------------------- 1 | import unicodeit 2 | 3 | 4 | def test_superscript_12(): 5 | assert unicodeit.replace('a^{12}') == 'a¹²' 6 | 7 | 8 | def test_superscript_minus1(): 9 | assert unicodeit.replace('cm^{-1}') == 'cm⁻¹' 10 | 11 | 12 | def test_subscript_12(): 13 | assert unicodeit.replace('a_{12}') == 'a₁₂' 14 | 15 | 16 | def test_subscript_minus1(): 17 | assert unicodeit.replace('cm_{-1}') == 'cm₋₁' 18 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = [{ 4 | mode: 'development', 5 | entry: './ts_src/ui.ts', 6 | devtool: 'inline-source-map', 7 | module: { 8 | rules: [ 9 | { 10 | test: /\.tsx?$/, 11 | use: 'ts-loader', 12 | exclude: /node_modules/, 13 | }, 14 | ], 15 | }, 16 | resolve: { 17 | extensions: [ '.tsx', '.ts', '.js' ], 18 | }, 19 | output: { 20 | filename: 'ui.js', 21 | path: path.resolve(__dirname, 'web'), 22 | }, 23 | }]; 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ent.xml 2 | *.workflow.zip 3 | 4 | .DS_Store 5 | *.py[cod] 6 | venv*/ 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Packages 12 | *.egg 13 | *.egg-info 14 | dist 15 | build 16 | eggs 17 | parts 18 | bin 19 | var 20 | sdist 21 | develop-eggs 22 | .installed.cfg 23 | lib 24 | lib64 25 | 26 | # Installer logs 27 | pip-log.txt 28 | 29 | # Unit test / coverage reports 30 | .coverage 31 | .tox 32 | nosetests.xml 33 | 34 | # Translations 35 | *.mo 36 | 37 | # Mr Developer 38 | .mr.developer.cfg 39 | .project 40 | .pydevproject 41 | 42 | .vscode/ 43 | 44 | # js 45 | ts_dist/ 46 | node_modules 47 | web/ui.js 48 | -------------------------------------------------------------------------------- /docs/dev.md: -------------------------------------------------------------------------------- 1 | Update version number in 2 | * `unicode/__init__.py` 3 | * `package.json` 4 | * in two places in `web/index.html` 5 | 6 | Do a github release. 7 | 8 | 9 | ================== 10 | OLD: 11 | 12 | # Python Release 13 | 14 | ```sh 15 | # python checks 16 | pytest 17 | pylint unicodeit 18 | 19 | # create package and upload 20 | python setup.py sdist 21 | twine upload dist/unicodeit... 22 | ``` 23 | 24 | 25 | # NPM Release 26 | 27 | ```sh 28 | # update typescript data 29 | python -m unicodeit.export_data 30 | 31 | # typescript checks 32 | npm run lint 33 | npm run test 34 | 35 | # rebuild typescript bundles 36 | npm run build 37 | 38 | # publish 39 | npm publish 40 | ``` 41 | 42 | 43 | # Website update 44 | 45 | ```sh 46 | # follow steps of NPM release first 47 | 48 | # push web folder to gh-pages branch 49 | ghp-import --no-jekyll --push web 50 | ``` 51 | -------------------------------------------------------------------------------- /ts_src/tests.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { replace } from './replace'; 3 | 4 | 5 | describe('Symbols', () => { 6 | describe('replace alpha', () => { 7 | it('converts', done => { 8 | expect(replace('\\alpha')).to.equal('α'); 9 | done(); 10 | }); 11 | }); 12 | 13 | describe('combining mark', () => { 14 | it('adds dot to a', done => { 15 | expect(replace('\\dot{a}')).to.equal('ȧ'); 16 | done(); 17 | }); 18 | it('adds dot to alpha', done => { 19 | expect(replace('\\dot{\\alpha}')).to.equal('α̇'); 20 | done(); 21 | }); 22 | it('empty combining char', done => { 23 | expect(replace('\\breve{}')).to.equal('˘'); 24 | done(); 25 | }); 26 | it('incomplete combining char', done => { 27 | expect(replace('\\breve{')).to.equal('\\breve{'); 28 | done(); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | 4 | # extract version from __init__.py 5 | with open('unicodeit/__init__.py', 'r') as f: 6 | VERSION_LINE = [l for l in f if l.startswith('__version__')][0] 7 | VERSION = VERSION_LINE.split('=')[1].strip()[1:-1] 8 | 9 | 10 | setup( 11 | name='unicodeit', 12 | version=VERSION, 13 | packages=[ 14 | 'unicodeit', 15 | ], 16 | license='MIT', 17 | description='Converts LaTeX tags to unicode', 18 | long_description=open('README.md', encoding='utf-8').read(), 19 | long_description_content_type='text/markdown', 20 | author='Sven Kreiss', 21 | author_email='research@svenkreiss.com', 22 | url='https://github.com/svenkreiss/unicodeit', 23 | 24 | install_requires=[ 25 | ], 26 | extras_require={ 27 | 'dev': [ 28 | 'pytest', 29 | 'pylint', 30 | 'pycodestyle', 31 | ], 32 | }, 33 | ) 34 | -------------------------------------------------------------------------------- /tests/test_data.py: -------------------------------------------------------------------------------- 1 | import unicodeit 2 | 3 | 4 | def test_order_replacements(): 5 | expr_length = float('inf') 6 | for l, _ in unicodeit.data.REPLACEMENTS: 7 | assert len(l) <= expr_length 8 | expr_length = len(l) 9 | 10 | 11 | def test_order_subsuperscripts(): 12 | expr_length = float('inf') 13 | for l, _ in unicodeit.data.SUBSUPERSCRIPTS: 14 | assert len(l) <= expr_length 15 | expr_length = len(l) 16 | 17 | 18 | def test_order_combiningmarks(): 19 | expr_length = float('inf') 20 | for l, _ in unicodeit.data.COMBININGMARKS: 21 | assert len(l) <= expr_length 22 | expr_length = len(l) 23 | 24 | 25 | def test_combining_not_in_replacement(): 26 | replacement_latex = {l.replace('{}', ''): u for l, u in unicodeit.data.REPLACEMENTS} 27 | for l, u in unicodeit.data.COMBININGMARKS: 28 | l = l.replace('{}', '') 29 | if l not in replacement_latex: 30 | continue 31 | 32 | # if the same command is in "replacements", 33 | # it must not be the combining mark 34 | assert replacement_latex[l] != u 35 | 36 | 37 | def test_incomplete_combiningmark(): 38 | assert unicodeit.replace('\\breve{') == '\\breve{' 39 | -------------------------------------------------------------------------------- /unicodeit/export_data.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from .data import REPLACEMENTS, COMBININGMARKS, SUBSUPERSCRIPTS 4 | 5 | 6 | if __name__ == "__main__": 7 | outname = 'ts_src/data.ts' 8 | if len(sys.argv) == 2: 9 | outname = sys.argv[1] 10 | 11 | with open(outname, 'w') as f: 12 | f.write('// autogenerated with python -m unicodeit.export_data\n\n') 13 | 14 | f.write('export const replacements = [\n') 15 | for l, u in REPLACEMENTS: 16 | l = l.replace('\\', '\\\\') 17 | l = l.replace('\'', '\\\'') 18 | u = u.replace('\\', '\\\\') 19 | f.write(' [\'{}\', \'{}\'],\n'.format(l, u)) 20 | f.write('];\n\n') 21 | 22 | f.write('export const combiningmarks = [\n') 23 | for l, u in COMBININGMARKS: 24 | l = l.replace('\\', '\\\\') 25 | l = l.replace('\'', '\\\'') 26 | f.write(' [\'{}\', \'{}\'],\n' 27 | ''.format(l, u.encode('ascii', 'backslashreplace').decode())) 28 | f.write('];\n\n') 29 | 30 | f.write('export const subsuperscripts = [\n') 31 | for l, u in SUBSUPERSCRIPTS: 32 | f.write(' [\'{}\', \'{}\'],\n'.format(l, u)) 33 | f.write('];\n') 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Sven Kreiss, Kyle Cranmer and contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | ===================== 10 | 11 | Some symbols were extracted from: http://milde.users.sourceforge.net/LUCR/Math/data/unimathsymbols.txt 12 | which is Copyright 2011 by Günter Milde and licensed under the LaTeX Project Public License (LPPL) 13 | included here as LICENSE.LPPL. 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unicodeit", 3 | "version": "0.7.2", 4 | "description": "Converts LaTeX tags to unicode.", 5 | "main": "ts_dist/js/index.js", 6 | "types": "ts_dist/js/index.d.ts", 7 | "directories": { 8 | "test": "tests" 9 | }, 10 | "files": [ 11 | "ts_dist/**/*" 12 | ], 13 | "scripts": { 14 | "build": "tsc && webpack", 15 | "watch-tsc": "tsc --watch", 16 | "watch-web": "webpack --watch", 17 | "lint": "eslint ts_src --ext .js,.jsx,.ts,.tsx", 18 | "test": "tsc && mocha ./ts_dist/js/tests.js" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/svenkreiss/unicodeit.git" 23 | }, 24 | "author": "Sven Kreiss", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/svenkreiss/unicodeit/issues" 28 | }, 29 | "homepage": "https://github.com/svenkreiss/unicodeit#readme", 30 | "devDependencies": { 31 | "@types/chai": "^4.2.11", 32 | "@types/mocha": "^7.0.2", 33 | "@typescript-eslint/eslint-plugin": "^3.5.0", 34 | "@typescript-eslint/parser": "^3.5.0", 35 | "chai": "^4.2.0", 36 | "eslint": "^7.4.0", 37 | "mocha": "^8.0.1", 38 | "ts-loader": "^7.0.5", 39 | "typescript": "^3.9.6", 40 | "webpack": "^4.43.0", 41 | "webpack-cli": "^3.3.12" 42 | }, 43 | "dependencies": { 44 | "@types/typeahead": "^0.11.32", 45 | "typeahead": "^0.2.2" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import sys 3 | 4 | import pytest 5 | 6 | 7 | PYTHON = 'python3' if sys.platform != 'win32' else 'python' 8 | 9 | 10 | def test_cli_symbols1(): 11 | r = subprocess.check_output([ 12 | PYTHON, '-m', 'unicodeit.cli', 13 | '\\Sigma' 14 | ]) 15 | print(r.decode()) 16 | assert r.decode().strip() == 'Σ' 17 | 18 | 19 | def test_cli_symbols2(): 20 | r = subprocess.check_output([ 21 | PYTHON, '-m', 'unicodeit.cli', 22 | 'def\\Sigma_{01234}abc\\alpha_{567}ggg\\beta_{1234}lll "\\Sigma e_0 e^3"' 23 | ]) 24 | print(r.decode()) 25 | assert r.decode().strip() == 'defΣ₀₁₂₃₄abcα₅₆₇gggβ₁₂₃₄lll "Σ e₀ e³"' 26 | 27 | 28 | def test_cli_symbols3(): 29 | r = subprocess.check_output([ 30 | PYTHON, '-m', 'unicodeit.cli', 31 | 'def^{01234}abc\\alpha^{567abc} "\\:) \\:G"' 32 | ]) 33 | print(r.decode()) 34 | assert r.decode().strip() == 'def⁰¹²³⁴abcα⁵⁶⁷ᵃᵇᶜ "☺ ㋡"' 35 | 36 | 37 | @pytest.mark.skip('this was already broken') 38 | def test_cli_symbols4(): 39 | r = subprocess.check_output([ 40 | PYTHON, '-m', 'unicodeit.cli', 41 | 'ggg\\beta^{1234=\\(5\\)}lll' 42 | ]) 43 | print(r.decode()) 44 | assert r.decode().strip() == 'Σ' 45 | 46 | 47 | def test_subscripts(): 48 | r = subprocess.check_output([ 49 | PYTHON, '-m', 'unicodeit.cli', 50 | 'a_{\\beta\\gamma\\varphi\\rho\\chi}' 51 | ]) 52 | print(r.decode()) 53 | assert r.decode().strip() == 'aᵦᵧᵩᵨᵪ' 54 | 55 | 56 | def test_superscripts(): 57 | r = subprocess.check_output([ 58 | PYTHON, '-m', 'unicodeit.cli', 59 | 'm^{ABDEGHIJKLMNOPRTUWabcdefghiklmnoprstuvwxyz\\beta\\gamma\\delta\\varphi\\chi<>}' 60 | ]) 61 | print(r.decode()) 62 | assert r.decode().strip() == 'mᴬᴮᴰᴱᴳᴴᴵᴶᴷᴸᴹᴺᴼᴾᴿᵀᵁᵂᵃᵇᶜᵈᵉᶠᵍʰⁱᵏˡᵐⁿᵒᵖʳˢᵗᵘᵛʷˣʸᶻᵝᵞᵟᵠᵡ˂˃' 63 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | include: 12 | - os: ubuntu-latest 13 | python: 3.6 14 | - os: ubuntu-latest 15 | python: 3.7 16 | - os: ubuntu-latest 17 | python: 3.8 18 | - os: macos-latest 19 | python: 3.7 20 | - os: windows-latest 21 | python: 3.7 22 | 23 | steps: 24 | - uses: actions/checkout@v2 25 | with: 26 | fetch-depth: 0 27 | - name: Set up Python ${{ matrix.python }} 28 | uses: actions/setup-python@v2 29 | with: 30 | python-version: ${{ matrix.python }} 31 | - name: Python version 32 | run: | 33 | python --version 34 | - name: Install 35 | run: | 36 | python -m pip install --upgrade pip 37 | python -m pip install -e ".[dev]" 38 | - name: Install JavaScript 39 | run: | 40 | npm install 41 | npm run build 42 | - name: Print environment 43 | run: | 44 | python -m pip freeze 45 | python --version 46 | python -c "import unicodeit; print(unicodeit.__version__)" 47 | - name: Lint 48 | run: pylint unicodeit --disable=fixme 49 | - name: Lint tests 50 | if: matrix.os != 'windows-latest' # because of path separator 51 | run: pylint tests/*.py --disable=fixme 52 | - name: pycodestyle 53 | run: python -m pycodestyle unicodeit 54 | - name: pycodestyle tests 55 | if: matrix.os != 'windows-latest' # because of path separator 56 | run: python -m pycodestyle tests/*.py 57 | - name: Test 58 | run: pytest -vv 59 | env: 60 | PYTHONIOENCODING: utf8 61 | - name: Test TS data is up-to-date 62 | if: matrix.os != 'windows-latest' # because of file encoding 63 | run: | 64 | python -m unicodeit.export_data ts_data_from_py.ts 65 | cmp -s ts_src/data.ts ts_data_from_py.ts 66 | - name: Lint js 67 | run: npm run lint 68 | - name: Test js 69 | run: npm run test 70 | - name: Build js 71 | run: npm run build 72 | -------------------------------------------------------------------------------- /ts_src/replace.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2010-2020 Sven Kreiss, Kyle Cranmer 2 | 3 | import { combiningmarks, replacements, subsuperscripts } from './data'; 4 | 5 | 6 | export function replace(f: string): string { 7 | // escape combining marks with a space after the backslash 8 | for (const ic in combiningmarks) { 9 | const c = combiningmarks[ic]; 10 | 11 | let i = -1; 12 | while ( 13 | (i = f.indexOf(c[0], i+1)) > -1 14 | && f.indexOf("}", i+1) > i 15 | ) { 16 | f = f.slice(0, i+1) + ' ' + f.slice(i+1); 17 | } 18 | } 19 | 20 | // console.log(replacements); 21 | for (const ir in replacements) { 22 | const r = replacements[ir]; 23 | // dirty way of a replaceAll(): 24 | f = f.split(r[0]).join(r[1]); 25 | 26 | if (r[0].slice(-2) == '{}') { 27 | f = f.split('\\ '+r[0].slice(1)).join(r[1]); 28 | } 29 | } 30 | 31 | // expand groups of subscripts: _{01234} 32 | let isub = -1; 33 | while ( 34 | (isub = f.indexOf("_{", isub+1)) > -1 35 | && f.indexOf("}", isub+1) > isub 36 | ) { 37 | f = f.slice(0, isub) + '_' + f[isub+2] + '_{' + f.slice(isub+3); 38 | f = f.replace('_{}', ''); 39 | } 40 | 41 | // expand groups of superscripts: ^{01234} 42 | let isup = -1; 43 | while ( 44 | (isup = f.indexOf("^{", isup+1)) > -1 45 | && f.indexOf("}", isup+1) > isup 46 | ) { 47 | f = f.slice(0, isup) + '^' + f[isup+2] + '^{' + f.slice(isup+3); 48 | f = f.replace('^{}', ''); 49 | } 50 | 51 | // now replace subsuperscripts 52 | for (const ir in subsuperscripts) { 53 | const r = subsuperscripts[ir]; 54 | // dirty way of a replaceAll(): 55 | f = f.split(r[0]).join(r[1]); 56 | } 57 | 58 | // combining marks (unicode char modifies previous char) 59 | for (const ic in combiningmarks) { 60 | const c = combiningmarks[ic]; 61 | 62 | let i = -1; 63 | while ( 64 | (i = f.indexOf('\\ '+c[0].slice(1)+'{', i+1)) > -1 65 | && f.indexOf("}", i+1) > i 66 | ) { 67 | const newString = f[i+c[0].length+2] + c[1]; 68 | f = f.slice(0,i)+newString+f.slice(i+1+c[0].length+3); 69 | } 70 | } 71 | 72 | return f; 73 | } 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UnicodeIt 2 | 3 | Tested on Linux, Mac and Windows: ![Tests](https://github.com/svenkreiss/unicodeit/workflows/Tests/badge.svg) 4 | 5 | Converts LaTeX tags to unicode. 6 | Available online at [unicodeit.net](https://www.unicodeit.net). 7 | 8 | 9 | ## Examples 10 | 11 | ``` 12 | \alpha α, \beta β, \infty ∞ e^+ e⁺, \mu^- μ⁻ \exists ∃, \nexists ∄ 13 | \int ∫, \sum ∑, \partial ∂ \to →, p\bar{p} pp̅ \mathcal{H} ℋ, \mathbb{R} ℝ 14 | \slash{\partial} ∂̸ \underline{x} x̲ \phone ☎, \checkmark ✓ 15 | \dot{x} ẋ, \ddot{x} ẍ A^6 A⁶, m_0 m₀ \Im ℑ, \Re ℜ, \hbar ℏ 16 | \gamma γ, \Gamma Γ \~{O} Õ \perp ⊥, \parallel ∥ 17 | \sfrac{3}{5} ⅗ \therefore ∴, \because ∵ \subset ⊂, \supset ⊃ 18 | ``` 19 | 20 | 21 | ## Python 22 | 23 | Install with `pip install unicodeit` and run 24 | 25 | ```sh 26 | python -m unicodeit.cli \\alpha 27 | ``` 28 | 29 | or in Python 30 | 31 | ```py 32 | import unicodeit 33 | print(unicodeit.replace('\\alpha')) 34 | ``` 35 | 36 | 37 | ## JavaScript / TypeScript 38 | 39 | Install with `npm install unicodeit --save-dev` and use it like this: 40 | 41 | ```js 42 | var unicodeit = require('unicodeit'); 43 | console.log(unicodeit.replace('\\alpha')); 44 | ``` 45 | 46 | 47 | ## Mac Automator 48 | 49 | Create your own Automator Workflow: 50 | 51 | * Create a new "Quick Action" (might also be labeled as "Service"). 52 | * At the top, leave the defaults: "Service receives *selected text* in *any application*" 53 | * Select the checkmark "output replaces selected text". 54 | * Add the action "Run Shell Script". 55 | * From dropdown, select to "pass in: as arguments". 56 | * The command is: `/usr/local/bin/python3 -m unicodeit.cli $1`. This Python interpreter must have unicodeit installed; e.g. with `/usr/local/bin/python3 -m pip install unicodeit`. 57 | * It should look something like this: 58 | 59 | ![automator script](docs/automator.png) 60 | 61 | To set a keyboard shortcut, go to `System Preferences` → 62 | `Keyboard` → `Shortcuts` → `Services` → `Text` → `UnicodeItAction`. 63 | Choose a keyboard shortcut like `Command+Option+Shift U`. 64 | 65 | Now you are all set to use your new keyboard shortcut in many apps, like here in Keynote: 66 | 67 | ![keynote_demo](docs/unicodeit_demo.gif) 68 | -------------------------------------------------------------------------------- /unicodeit/replace.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2010 Sven Kreiss, Kyle Cranmer 2 | import re 3 | 4 | from .data import REPLACEMENTS, COMBININGMARKS, SUBSUPERSCRIPTS 5 | 6 | 7 | def replace(f: str): 8 | # escape combining marks with a space after the backslash 9 | for c in COMBININGMARKS: 10 | f = f.replace(c[0] + '{', '\\ ' + c[0][1:] + '{') 11 | 12 | # replace 13 | for r in REPLACEMENTS: 14 | f = f.replace(r[0], r[1]) 15 | 16 | # check whether it was escaped for combining marks but has empty braces 17 | if r[0].endswith('{}'): 18 | f = f.replace('\\ ' + r[0][1:], r[1]) 19 | 20 | # expand groups of subscripts: \_{01234} 21 | offset = 0 22 | for s in re.finditer( 23 | r"_\{[0-9\+-=\(\)<>\-aeoxjhklmnpstiruv" 24 | r"\u03B2\u03B3\u03C1\u03C6\u03C7\u2212]+\}", f): 25 | newstring, n = re.subn( 26 | r"([0-9\+-=\(\)<>\-aeoxjhklmnpstiruv" 27 | r"\u03B2\u03B3\u03C1\u03C6\u03C7\u2212])", 28 | r"_\1", s.group(0)[2:-1]) 29 | f = f[:s.start() + offset] + newstring + f[s.end() + offset:] 30 | offset += n * 2 - (n + 3) 31 | 32 | # expand groups of superscripts: \^{01234} 33 | offset = 0 34 | for s in re.finditer( 35 | r"\^\{[0-9\+-=\(\)<>ABDEGHIJKLMNOPRTUW" 36 | r"abcdefghijklmnoprstuvwxyz" 37 | r"\u03B2\u03B3\u03B4\u03C6\u03C7\u222B\u2212]+\}", f): 38 | newstring, n = re.subn( 39 | r"([0-9\+-=\(\)<>ABDEGHIJKLMNOPRTUW" 40 | r"abcdefghijklmnoprstuvwxyz" 41 | r"\u03B2\u03B3\u03B4\u03C6\u03C7\u222B\u2212])", 42 | r"^\1", s.group(0)[2:-1]) 43 | f = f[:s.start() + offset] + newstring + f[s.end() + offset:] 44 | offset += n * 2 - (n + 3) 45 | 46 | # now replace subsuperscripts 47 | for r in SUBSUPERSCRIPTS: 48 | f = f.replace(r[0], r[1]) 49 | 50 | # process combining marks first 51 | for c in COMBININGMARKS: 52 | escaped_latex = '\\ {}{{'.format(c[0][1:]) 53 | while escaped_latex in f: 54 | i = f.index(escaped_latex) 55 | if len(f) <= i + len(escaped_latex): 56 | # incomplete: unescape and continue 57 | f = f[:i] + c[0] + '{' 58 | continue 59 | 60 | combined_char = f[i + len(escaped_latex)] 61 | 62 | remainder = '' 63 | if len(f) >= i + len(escaped_latex) + 2: 64 | remainder = f[i + len(escaped_latex) + 2:] 65 | 66 | f = f[:i] + combined_char + c[1] + remainder 67 | 68 | return f 69 | -------------------------------------------------------------------------------- /ts_src/ui.ts: -------------------------------------------------------------------------------- 1 | import {replacements} from './data'; 2 | import {replace} from './replace'; 3 | 4 | const latexInput = $('#latexInput'); 5 | const unicodeOutput = $('#unicodeOutput'); 6 | const permaLink = $('.permalink'); 7 | 8 | 9 | // copy replacements and sort case insensitive 10 | let listOfReplacements = replacements 11 | .map(function(r) { return { value: r[0], unicode: r[1] }; }) 12 | .sort(function(a, b) { return a.value.toLowerCase().localeCompare(b.value.toLowerCase()); }); 13 | 14 | // reorder such that when just typing '\' suggestions starting with '\a' appear 15 | const indexOfFirstA = listOfReplacements 16 | .map(function(r) { return r.value.slice(0, 2).toLowerCase(); }) 17 | .indexOf('\\a'); 18 | listOfReplacements = listOfReplacements.slice(indexOfFirstA).concat(listOfReplacements.slice(0, indexOfFirstA)); 19 | 20 | 21 | // Bloodhound: the source (dataset) for typeahead 22 | const mySource = new Bloodhound({ 23 | datumTokenizer: function(d) { return Bloodhound.tokenizers.whitespace(d.value); }, 24 | queryTokenizer: function(d) { const i = d.lastIndexOf('\\'); const r = [d.substr(0, i), d.substr(i)]; console.log(r); return r; }, 25 | local: listOfReplacements, 26 | }); 27 | mySource.initialize(); 28 | 29 | // apply typeahead to input text field 30 | latexInput.typeahead({ 31 | hint: false, 32 | highlight: true, 33 | minLength: 0, 34 | }, { 35 | display: 'value', 36 | source: mySource.ttAdapter(), 37 | limit: 15, 38 | templates: { 39 | suggestion: function(datum: {unicode:string, value:string}) { 40 | return '
'+datum.unicode+''+datum.value+'
'; 41 | }, 42 | }, 43 | }); 44 | 45 | 46 | latexInput.on('typeahead:selected', function (object, datum) { 47 | $('input#unicodeOutput').val(datum.unicode); 48 | }); 49 | // $('.tt-query').css('background-color','#fff'); 50 | latexInput.focus(); 51 | 52 | 53 | // click handler for LaTeX examples 54 | $('.latexExample').on('click', function() { 55 | latexInput 56 | .typeahead('val', $(this).html()) 57 | .trigger('change') 58 | .focus(); 59 | }); 60 | 61 | // generate unicode output and permalink 62 | latexInput.on('keyup change', function() { 63 | const input = $(this).val(); 64 | unicodeOutput.val(replace(input)); 65 | permaLink.attr('href', 'https://www.unicodeit.net/?'+encodeURIComponent(input)); 66 | }); 67 | 68 | 69 | if (location.search) { 70 | const latex = decodeURIComponent(location.search.slice(1)); 71 | latexInput 72 | .typeahead('val', latex) 73 | .trigger('change') 74 | .focus(); 75 | } 76 | -------------------------------------------------------------------------------- /web/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Helvetica Neue", helvetica, arial; 3 | padding: 30px 15px 30px 15px; 4 | color:#999; 5 | } 6 | 7 | h1 { color:#55C; margin-top:0; } 8 | .banner_it { color:#000; } 9 | h1 small { font-size:40%; } 10 | 11 | .leftColumn, .rightColumn { margin-top:50px; } 12 | 13 | #content_manage { display:none; } 14 | #content_participate { display:none; } 15 | 16 | .subtitle { font-size:50%; color:#888; } 17 | .beta { font-size:40%; color:#ccc; } 18 | 19 | .large_stat { font-size:300%; } 20 | .raw { word-wrap:break-word; } 21 | 22 | .footer { color:#ccc; font-size:80%; } 23 | .footer a { color:#ccc; } 24 | 25 | ul { 26 | list-style: none; 27 | margin: 0; 28 | padding: 0; 29 | } 30 | 31 | ul li { 32 | line-height: 1.4; 33 | } 34 | 35 | input { margin:5px; } 36 | .latexExample { 37 | cursor:pointer; 38 | max-width:9em; 39 | overflow:hidden; 40 | text-overflow:ellipsis; 41 | } 42 | 43 | .permalink { 44 | display: inline-block; 45 | margin: 1em 1em 1em 0.5em; 46 | font-size: 85%; 47 | } 48 | 49 | 50 | 51 | 52 | 53 | 54 | .twitter-typeahead{ 55 | width:100%; 56 | } 57 | 58 | .twitter-typeahead .tt-query, 59 | .twitter-typeahead .tt-hint { 60 | margin-bottom: 0; 61 | } 62 | .tt-menu { 63 | min-width: 160px; 64 | margin-top: 2px; 65 | padding: 5px 0; 66 | background-color: #fff; 67 | border: 1px solid #ccc; 68 | border: 1px solid rgba(0,0,0,.2); 69 | *border-right-width: 2px; 70 | *border-bottom-width: 2px; 71 | -webkit-border-radius: 6px; 72 | -moz-border-radius: 6px; 73 | border-radius: 6px; 74 | -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); 75 | -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); 76 | box-shadow: 0 5px 10px rgba(0,0,0,.2); 77 | -webkit-background-clip: padding-box; 78 | -moz-background-clip: padding; 79 | background-clip: padding-box; 80 | width:100%; 81 | } 82 | 83 | .tt-suggestion { 84 | display: block; 85 | padding: 3px 20px; 86 | } 87 | 88 | .tt-suggestion:hover { 89 | cursor: pointer; 90 | color: #fff; 91 | background-color: #0081c2; 92 | background-image: -moz-linear-gradient(top, #0088cc, #0077b3); 93 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); 94 | background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); 95 | background-image: -o-linear-gradient(top, #0088cc, #0077b3); 96 | background-image: linear-gradient(to bottom, #0088cc, #0077b3); 97 | background-repeat: repeat-x; 98 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0) 99 | } 100 | 101 | .tt-suggestion p { 102 | margin: 0; 103 | } 104 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Build and upload 2 | 3 | # Build on every branch push, tag push, and pull request change: 4 | # on: [push, pull_request] 5 | # Alternatively, to publish when a (published) GitHub Release is created, use the following: 6 | on: 7 | push: 8 | branches: 9 | - master 10 | pull_request: 11 | branches: 12 | - master 13 | release: 14 | types: 15 | - published 16 | 17 | jobs: 18 | build_sdist: 19 | name: Build Python source distribution 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v2 23 | 24 | - uses: actions/setup-python@v2 25 | name: Install Python 26 | with: 27 | python-version: '3.7' 28 | 29 | - name: Build sdist 30 | run: python setup.py sdist 31 | 32 | - uses: actions/upload-artifact@v2 33 | with: 34 | path: dist/*.tar.gz 35 | 36 | upload_pypi: 37 | needs: [build_sdist] 38 | runs-on: ubuntu-latest 39 | # upload to PyPI on every tag starting with 'v' 40 | # if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v') 41 | # alternatively, to publish when a GitHub Release is created, use the following rule: 42 | if: github.event_name == 'release' && github.event.action == 'published' 43 | steps: 44 | - uses: actions/download-artifact@v2 45 | with: 46 | name: artifact 47 | path: dist 48 | 49 | - uses: pypa/gh-action-pypi-publish@master 50 | with: 51 | user: __token__ 52 | password: ${{ secrets.pypi_password }} 53 | # To test: repository_url: https://test.pypi.org/legacy/ 54 | 55 | build_npm: 56 | runs-on: ubuntu-latest 57 | steps: 58 | - uses: actions/checkout@v1 59 | - uses: actions/setup-node@v1 60 | with: 61 | node-version: 10 62 | - run: npm install 63 | - run: npm run lint 64 | - run: npm run test 65 | - run: npm run build 66 | 67 | publish_npm: 68 | needs: [build_npm] 69 | runs-on: ubuntu-latest 70 | if: github.event_name == 'release' && github.event.action == 'published' 71 | steps: 72 | - uses: actions/checkout@v1 73 | - uses: actions/setup-node@v1 74 | with: 75 | node-version: 10 76 | - run: npm install 77 | - run: npm run lint 78 | - run: npm run test 79 | - run: npm run build 80 | - uses: JS-DevTools/npm-publish@v1 81 | with: 82 | token: ${{ secrets.NPM_TOKEN }} 83 | 84 | publish_web: 85 | runs-on: ubuntu-latest 86 | if: github.event_name == 'release' && github.event.action == 'published' 87 | steps: 88 | - uses: actions/checkout@v1 89 | - uses: actions/setup-node@v1 90 | with: 91 | node-version: 10 92 | - run: npm install 93 | - run: npm run lint 94 | - run: npm run test 95 | - run: npm run build 96 | 97 | - name: Deploy 98 | uses: peaceiris/actions-gh-pages@v3 99 | with: 100 | github_token: ${{ secrets.GITHUB_TOKEN }} 101 | publish_dir: ./web 102 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | unicodeit.net 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 |

unicode.net β testing

19 |
20 | 21 |
22 |

Online Demo

23 |
24 |
25 | 26 |
27 |
28 | 29 |
30 |
31 |

32 | 33 |

34 |
35 |
36 | 37 |
38 |
39 |

Created by Sven Kreiss and Kyle Cranmer.
40 | Maintained on GitHub.

41 | 42 | 43 |

44 | 45 | 46 | 47 | 48 |

49 | 50 | 51 | 52 |
53 |
54 | 55 |

56 | 57 |

Python / JavaScript / Automator

58 | 59 |

60 | All the info in the README file. 61 |

62 | 63 | 64 |

Help

65 | 66 |

Type LaTeX expressions in the input box on the left. The converted text in the box on the right can be copied to most programs including PowerPoint and Keynote, e-mail clients like Outlook and Mail and even apps on smart phones. UnicodeIt can create greek letters, arrows, mathematical symbols and many more for presentations, emails, chats, facebook, etc.

67 | 68 |
69 | 70 |
Examples
71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
x \in (-\infty, \infty)x ∈ (-∞, ∞)
p\bar{p} \to \mu^+\mu^-pp̅ → μ⁺μ⁻
\alpha\omega\epsilon\S\om\inαωε§øm∈
^2H ^6Li ^{10}B ^{14}N²H ⁶Li ¹⁰B ¹⁴N
\mathcal{L} \mathcal{H} \mathbb{R} \mathbb{C}ℒ ℋ ℝ ℂ
80 |
81 | 82 |
83 |
84 |



85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /LICENSE.LPPL: -------------------------------------------------------------------------------- 1 | The LaTeX Project Public License 2 | =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 3 | 4 | LPPL Version 1.3c 2008-05-04 5 | 6 | Copyright 1999 2002-2008 LaTeX3 Project 7 | Everyone is allowed to distribute verbatim copies of this 8 | license document, but modification of it is not allowed. 9 | 10 | 11 | PREAMBLE 12 | ======== 13 | 14 | The LaTeX Project Public License (LPPL) is the primary license under 15 | which the LaTeX kernel and the base LaTeX packages are distributed. 16 | 17 | You may use this license for any work of which you hold the copyright 18 | and which you wish to distribute. This license may be particularly 19 | suitable if your work is TeX-related (such as a LaTeX package), but 20 | it is written in such a way that you can use it even if your work is 21 | unrelated to TeX. 22 | 23 | The section `WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE', 24 | below, gives instructions, examples, and recommendations for authors 25 | who are considering distributing their works under this license. 26 | 27 | This license gives conditions under which a work may be distributed 28 | and modified, as well as conditions under which modified versions of 29 | that work may be distributed. 30 | 31 | We, the LaTeX3 Project, believe that the conditions below give you 32 | the freedom to make and distribute modified versions of your work 33 | that conform with whatever technical specifications you wish while 34 | maintaining the availability, integrity, and reliability of 35 | that work. If you do not see how to achieve your goal while 36 | meeting these conditions, then read the document `cfgguide.tex' 37 | and `modguide.tex' in the base LaTeX distribution for suggestions. 38 | 39 | 40 | DEFINITIONS 41 | =========== 42 | 43 | In this license document the following terms are used: 44 | 45 | `Work' 46 | Any work being distributed under this License. 47 | 48 | `Derived Work' 49 | Any work that under any applicable law is derived from the Work. 50 | 51 | `Modification' 52 | Any procedure that produces a Derived Work under any applicable 53 | law -- for example, the production of a file containing an 54 | original file associated with the Work or a significant portion of 55 | such a file, either verbatim or with modifications and/or 56 | translated into another language. 57 | 58 | `Modify' 59 | To apply any procedure that produces a Derived Work under any 60 | applicable law. 61 | 62 | `Distribution' 63 | Making copies of the Work available from one person to another, in 64 | whole or in part. Distribution includes (but is not limited to) 65 | making any electronic components of the Work accessible by 66 | file transfer protocols such as FTP or HTTP or by shared file 67 | systems such as Sun's Network File System (NFS). 68 | 69 | `Compiled Work' 70 | A version of the Work that has been processed into a form where it 71 | is directly usable on a computer system. This processing may 72 | include using installation facilities provided by the Work, 73 | transformations of the Work, copying of components of the Work, or 74 | other activities. Note that modification of any installation 75 | facilities provided by the Work constitutes modification of the Work. 76 | 77 | `Current Maintainer' 78 | A person or persons nominated as such within the Work. If there is 79 | no such explicit nomination then it is the `Copyright Holder' under 80 | any applicable law. 81 | 82 | `Base Interpreter' 83 | A program or process that is normally needed for running or 84 | interpreting a part or the whole of the Work. 85 | 86 | A Base Interpreter may depend on external components but these 87 | are not considered part of the Base Interpreter provided that each 88 | external component clearly identifies itself whenever it is used 89 | interactively. Unless explicitly specified when applying the 90 | license to the Work, the only applicable Base Interpreter is a 91 | `LaTeX-Format' or in the case of files belonging to the 92 | `LaTeX-format' a program implementing the `TeX language'. 93 | 94 | 95 | 96 | CONDITIONS ON DISTRIBUTION AND MODIFICATION 97 | =========================================== 98 | 99 | 1. Activities other than distribution and/or modification of the Work 100 | are not covered by this license; they are outside its scope. In 101 | particular, the act of running the Work is not restricted and no 102 | requirements are made concerning any offers of support for the Work. 103 | 104 | 2. You may distribute a complete, unmodified copy of the Work as you 105 | received it. Distribution of only part of the Work is considered 106 | modification of the Work, and no right to distribute such a Derived 107 | Work may be assumed under the terms of this clause. 108 | 109 | 3. You may distribute a Compiled Work that has been generated from a 110 | complete, unmodified copy of the Work as distributed under Clause 2 111 | above, as long as that Compiled Work is distributed in such a way that 112 | the recipients may install the Compiled Work on their system exactly 113 | as it would have been installed if they generated a Compiled Work 114 | directly from the Work. 115 | 116 | 4. If you are the Current Maintainer of the Work, you may, without 117 | restriction, modify the Work, thus creating a Derived Work. You may 118 | also distribute the Derived Work without restriction, including 119 | Compiled Works generated from the Derived Work. Derived Works 120 | distributed in this manner by the Current Maintainer are considered to 121 | be updated versions of the Work. 122 | 123 | 5. If you are not the Current Maintainer of the Work, you may modify 124 | your copy of the Work, thus creating a Derived Work based on the Work, 125 | and compile this Derived Work, thus creating a Compiled Work based on 126 | the Derived Work. 127 | 128 | 6. If you are not the Current Maintainer of the Work, you may 129 | distribute a Derived Work provided the following conditions are met 130 | for every component of the Work unless that component clearly states 131 | in the copyright notice that it is exempt from that condition. Only 132 | the Current Maintainer is allowed to add such statements of exemption 133 | to a component of the Work. 134 | 135 | a. If a component of this Derived Work can be a direct replacement 136 | for a component of the Work when that component is used with the 137 | Base Interpreter, then, wherever this component of the Work 138 | identifies itself to the user when used interactively with that 139 | Base Interpreter, the replacement component of this Derived Work 140 | clearly and unambiguously identifies itself as a modified version 141 | of this component to the user when used interactively with that 142 | Base Interpreter. 143 | 144 | b. Every component of the Derived Work contains prominent notices 145 | detailing the nature of the changes to that component, or a 146 | prominent reference to another file that is distributed as part 147 | of the Derived Work and that contains a complete and accurate log 148 | of the changes. 149 | 150 | c. No information in the Derived Work implies that any persons, 151 | including (but not limited to) the authors of the original version 152 | of the Work, provide any support, including (but not limited to) 153 | the reporting and handling of errors, to recipients of the 154 | Derived Work unless those persons have stated explicitly that 155 | they do provide such support for the Derived Work. 156 | 157 | d. You distribute at least one of the following with the Derived Work: 158 | 159 | 1. A complete, unmodified copy of the Work; 160 | if your distribution of a modified component is made by 161 | offering access to copy the modified component from a 162 | designated place, then offering equivalent access to copy 163 | the Work from the same or some similar place meets this 164 | condition, even though third parties are not compelled to 165 | copy the Work along with the modified component; 166 | 167 | 2. Information that is sufficient to obtain a complete, 168 | unmodified copy of the Work. 169 | 170 | 7. If you are not the Current Maintainer of the Work, you may 171 | distribute a Compiled Work generated from a Derived Work, as long as 172 | the Derived Work is distributed to all recipients of the Compiled 173 | Work, and as long as the conditions of Clause 6, above, are met with 174 | regard to the Derived Work. 175 | 176 | 8. The conditions above are not intended to prohibit, and hence do not 177 | apply to, the modification, by any method, of any component so that it 178 | becomes identical to an updated version of that component of the Work as 179 | it is distributed by the Current Maintainer under Clause 4, above. 180 | 181 | 9. Distribution of the Work or any Derived Work in an alternative 182 | format, where the Work or that Derived Work (in whole or in part) is 183 | then produced by applying some process to that format, does not relax or 184 | nullify any sections of this license as they pertain to the results of 185 | applying that process. 186 | 187 | 10. a. A Derived Work may be distributed under a different license 188 | provided that license itself honors the conditions listed in 189 | Clause 6 above, in regard to the Work, though it does not have 190 | to honor the rest of the conditions in this license. 191 | 192 | b. If a Derived Work is distributed under a different license, that 193 | Derived Work must provide sufficient documentation as part of 194 | itself to allow each recipient of that Derived Work to honor the 195 | restrictions in Clause 6 above, concerning changes from the Work. 196 | 197 | 11. This license places no restrictions on works that are unrelated to 198 | the Work, nor does this license place any restrictions on aggregating 199 | such works with the Work by any means. 200 | 201 | 12. Nothing in this license is intended to, or may be used to, prevent 202 | complete compliance by all parties with all applicable laws. 203 | 204 | 205 | NO WARRANTY 206 | =========== 207 | 208 | There is no warranty for the Work. Except when otherwise stated in 209 | writing, the Copyright Holder provides the Work `as is', without 210 | warranty of any kind, either expressed or implied, including, but not 211 | limited to, the implied warranties of merchantability and fitness for a 212 | particular purpose. The entire risk as to the quality and performance 213 | of the Work is with you. Should the Work prove defective, you assume 214 | the cost of all necessary servicing, repair, or correction. 215 | 216 | In no event unless required by applicable law or agreed to in writing 217 | will The Copyright Holder, or any author named in the components of the 218 | Work, or any other party who may distribute and/or modify the Work as 219 | permitted above, be liable to you for damages, including any general, 220 | special, incidental or consequential damages arising out of any use of 221 | the Work or out of inability to use the Work (including, but not limited 222 | to, loss of data, data being rendered inaccurate, or losses sustained by 223 | anyone as a result of any failure of the Work to operate with any other 224 | programs), even if the Copyright Holder or said author or said other 225 | party has been advised of the possibility of such damages. 226 | 227 | 228 | MAINTENANCE OF THE WORK 229 | ======================= 230 | 231 | The Work has the status `author-maintained' if the Copyright Holder 232 | explicitly and prominently states near the primary copyright notice in 233 | the Work that the Work can only be maintained by the Copyright Holder 234 | or simply that it is `author-maintained'. 235 | 236 | The Work has the status `maintained' if there is a Current Maintainer 237 | who has indicated in the Work that they are willing to receive error 238 | reports for the Work (for example, by supplying a valid e-mail 239 | address). It is not required for the Current Maintainer to acknowledge 240 | or act upon these error reports. 241 | 242 | The Work changes from status `maintained' to `unmaintained' if there 243 | is no Current Maintainer, or the person stated to be Current 244 | Maintainer of the work cannot be reached through the indicated means 245 | of communication for a period of six months, and there are no other 246 | significant signs of active maintenance. 247 | 248 | You can become the Current Maintainer of the Work by agreement with 249 | any existing Current Maintainer to take over this role. 250 | 251 | If the Work is unmaintained, you can become the Current Maintainer of 252 | the Work through the following steps: 253 | 254 | 1. Make a reasonable attempt to trace the Current Maintainer (and 255 | the Copyright Holder, if the two differ) through the means of 256 | an Internet or similar search. 257 | 258 | 2. If this search is successful, then enquire whether the Work 259 | is still maintained. 260 | 261 | a. If it is being maintained, then ask the Current Maintainer 262 | to update their communication data within one month. 263 | 264 | b. If the search is unsuccessful or no action to resume active 265 | maintenance is taken by the Current Maintainer, then announce 266 | within the pertinent community your intention to take over 267 | maintenance. (If the Work is a LaTeX work, this could be 268 | done, for example, by posting to comp.text.tex.) 269 | 270 | 3a. If the Current Maintainer is reachable and agrees to pass 271 | maintenance of the Work to you, then this takes effect 272 | immediately upon announcement. 273 | 274 | b. If the Current Maintainer is not reachable and the Copyright 275 | Holder agrees that maintenance of the Work be passed to you, 276 | then this takes effect immediately upon announcement. 277 | 278 | 4. If you make an `intention announcement' as described in 2b. above 279 | and after three months your intention is challenged neither by 280 | the Current Maintainer nor by the Copyright Holder nor by other 281 | people, then you may arrange for the Work to be changed so as 282 | to name you as the (new) Current Maintainer. 283 | 284 | 5. If the previously unreachable Current Maintainer becomes 285 | reachable once more within three months of a change completed 286 | under the terms of 3b) or 4), then that Current Maintainer must 287 | become or remain the Current Maintainer upon request provided 288 | they then update their communication data within one month. 289 | 290 | A change in the Current Maintainer does not, of itself, alter the fact 291 | that the Work is distributed under the LPPL license. 292 | 293 | If you become the Current Maintainer of the Work, you should 294 | immediately provide, within the Work, a prominent and unambiguous 295 | statement of your status as Current Maintainer. You should also 296 | announce your new status to the same pertinent community as 297 | in 2b) above. 298 | 299 | 300 | WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE 301 | ====================================================== 302 | 303 | This section contains important instructions, examples, and 304 | recommendations for authors who are considering distributing their 305 | works under this license. These authors are addressed as `you' in 306 | this section. 307 | 308 | Choosing This License or Another License 309 | ---------------------------------------- 310 | 311 | If for any part of your work you want or need to use *distribution* 312 | conditions that differ significantly from those in this license, then 313 | do not refer to this license anywhere in your work but, instead, 314 | distribute your work under a different license. You may use the text 315 | of this license as a model for your own license, but your license 316 | should not refer to the LPPL or otherwise give the impression that 317 | your work is distributed under the LPPL. 318 | 319 | The document `modguide.tex' in the base LaTeX distribution explains 320 | the motivation behind the conditions of this license. It explains, 321 | for example, why distributing LaTeX under the GNU General Public 322 | License (GPL) was considered inappropriate. Even if your work is 323 | unrelated to LaTeX, the discussion in `modguide.tex' may still be 324 | relevant, and authors intending to distribute their works under any 325 | license are encouraged to read it. 326 | 327 | A Recommendation on Modification Without Distribution 328 | ----------------------------------------------------- 329 | 330 | It is wise never to modify a component of the Work, even for your own 331 | personal use, without also meeting the above conditions for 332 | distributing the modified component. While you might intend that such 333 | modifications will never be distributed, often this will happen by 334 | accident -- you may forget that you have modified that component; or 335 | it may not occur to you when allowing others to access the modified 336 | version that you are thus distributing it and violating the conditions 337 | of this license in ways that could have legal implications and, worse, 338 | cause problems for the community. It is therefore usually in your 339 | best interest to keep your copy of the Work identical with the public 340 | one. Many works provide ways to control the behavior of that work 341 | without altering any of its licensed components. 342 | 343 | How to Use This License 344 | ----------------------- 345 | 346 | To use this license, place in each of the components of your work both 347 | an explicit copyright notice including your name and the year the work 348 | was authored and/or last substantially modified. Include also a 349 | statement that the distribution and/or modification of that 350 | component is constrained by the conditions in this license. 351 | 352 | Here is an example of such a notice and statement: 353 | 354 | %% pig.dtx 355 | %% Copyright 2005 M. Y. Name 356 | % 357 | % This work may be distributed and/or modified under the 358 | % conditions of the LaTeX Project Public License, either version 1.3 359 | % of this license or (at your option) any later version. 360 | % The latest version of this license is in 361 | % http://www.latex-project.org/lppl.txt 362 | % and version 1.3 or later is part of all distributions of LaTeX 363 | % version 2005/12/01 or later. 364 | % 365 | % This work has the LPPL maintenance status `maintained'. 366 | % 367 | % The Current Maintainer of this work is M. Y. Name. 368 | % 369 | % This work consists of the files pig.dtx and pig.ins 370 | % and the derived file pig.sty. 371 | 372 | Given such a notice and statement in a file, the conditions 373 | given in this license document would apply, with the `Work' referring 374 | to the three files `pig.dtx', `pig.ins', and `pig.sty' (the last being 375 | generated from `pig.dtx' using `pig.ins'), the `Base Interpreter' 376 | referring to any `LaTeX-Format', and both `Copyright Holder' and 377 | `Current Maintainer' referring to the person `M. Y. Name'. 378 | 379 | If you do not want the Maintenance section of LPPL to apply to your 380 | Work, change `maintained' above into `author-maintained'. 381 | However, we recommend that you use `maintained', as the Maintenance 382 | section was added in order to ensure that your Work remains useful to 383 | the community even when you can no longer maintain and support it 384 | yourself. 385 | 386 | Derived Works That Are Not Replacements 387 | --------------------------------------- 388 | 389 | Several clauses of the LPPL specify means to provide reliability and 390 | stability for the user community. They therefore concern themselves 391 | with the case that a Derived Work is intended to be used as a 392 | (compatible or incompatible) replacement of the original Work. If 393 | this is not the case (e.g., if a few lines of code are reused for a 394 | completely different task), then clauses 6b and 6d shall not apply. 395 | 396 | 397 | Important Recommendations 398 | ------------------------- 399 | 400 | Defining What Constitutes the Work 401 | 402 | The LPPL requires that distributions of the Work contain all the 403 | files of the Work. It is therefore important that you provide a 404 | way for the licensee to determine which files constitute the Work. 405 | This could, for example, be achieved by explicitly listing all the 406 | files of the Work near the copyright notice of each file or by 407 | using a line such as: 408 | 409 | % This work consists of all files listed in manifest.txt. 410 | 411 | in that place. In the absence of an unequivocal list it might be 412 | impossible for the licensee to determine what is considered by you 413 | to comprise the Work and, in such a case, the licensee would be 414 | entitled to make reasonable conjectures as to which files comprise 415 | the Work. 416 | 417 | -------------------------------------------------------------------------------- /tests/test_v06symbols.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import sys 3 | 4 | import pytest 5 | 6 | 7 | PYTHON = 'python3' if sys.platform != 'win32' else 'python' 8 | 9 | 10 | SYMBOLS_V06 = [ 11 | (r'\textfractionsolidus', '\u2044'), 12 | (r'\leftrightsquigarrow', '\u21AD'), 13 | (r'\textpertenthousand', '\u2031'), 14 | (r'\blacktriangleright', '\u25B8'), 15 | (r'\blacktriangledown', '\u25BE'), 16 | (r'\blacktriangleleft', '\u25C2'), 17 | (r'\twoheadrightarrow', '\u21A0'), 18 | (r'\leftrightharpoons', '\u21CB'), 19 | (r'\rightleftharpoons', '\u21CC'), 20 | (r'\textreferencemark', '\u203B'), 21 | (r'\circlearrowright', '\u21BB'), 22 | (r'\rightrightarrows', '\u21C9'), 23 | (r'\vartriangleright', '\u22B3'), 24 | (r'\textordmasculine', '\u00BA'), 25 | (r'\textvisiblespace', '\u2423'), 26 | (r'\twoheadleftarrow', '\u219E'), 27 | (r'\downharpoonright', '\u21C2'), 28 | (r'\ntrianglerighteq', '\u22ED'), 29 | (r'\rightharpoondown', '\u21C1'), 30 | (r'\textperthousand', '\u2030'), 31 | (r'\leftrightarrows', '\u21C6'), 32 | (r'\textmusicalnote', '\u266A'), 33 | (r'\nleftrightarrow', '\u21AE'), 34 | (r'\rightleftarrows', '\u21C4'), 35 | (r'\bigtriangledown', '\u25BD'), 36 | (r'\textordfeminine', '\u00AA'), 37 | (r'\ntrianglelefteq', '\u22EC'), 38 | (r'\rightthreetimes', '\u22CC'), 39 | (r'\trianglerighteq', '\u22B5'), 40 | (r'\vartriangleleft', '\u22B2'), 41 | (r'\rightsquigarrow', '\u21DD'), 42 | (r'\downharpoonleft', '\u21C3'), 43 | (r'\curvearrowright', '\u21B7'), 44 | (r'\circlearrowleft', '\u21BA'), 45 | (r'\leftharpoondown', '\u21BD'), 46 | (r'\nLeftrightarrow', '\u21CE'), 47 | (r'\curvearrowleft', '\u21B6'), 48 | (r'\guilsinglright', '\u203A'), 49 | (r'\leftthreetimes', '\u22CB'), 50 | (r'\leftrightarrow', '\u2194'), 51 | (r'\rightharpoonup', '\u21C0'), 52 | (r'\guillemotright', '\u00BB'), 53 | (r'\downdownarrows', '\u21CA'), 54 | (r'\hookrightarrow', '\u21AA'), 55 | (r'\hspace{0.25em}', '\u2005'), 56 | (r'\dashrightarrow', '\u21E2'), 57 | (r'\leftleftarrows', '\u21C7'), 58 | (r'\trianglelefteq', '\u22B4'), 59 | (r'\ntriangleright', '\u22EB'), 60 | (r'\doublebarwedge', '\u2306'), 61 | (r'\upharpoonright', '\u21BE'), 62 | (r'\rightarrowtail', '\u21A3'), 63 | (r'\looparrowright', '\u21AC'), 64 | (r'\Leftrightarrow', '\u21D4'), 65 | (r'\sphericalangle', '\u2222'), 66 | (r'\divideontimes', '\u22C7'), 67 | (r'\measuredangle', '\u2221'), 68 | (r'\blacktriangle', '\u25B4'), 69 | (r'\ntriangleleft', '\u22EA'), 70 | # (r'\mathchar"1356', '\u2041'), 71 | (r'\texttrademark', '\u2122'), 72 | # (r'\\mathchar"2208', '\u2316'), 73 | (r'\triangleright', '\u25B9'), 74 | (r'\leftarrowtail', '\u21A2'), 75 | (r'\guilsinglleft', '\u2039'), 76 | (r'\upharpoonleft', '\u21BF'), 77 | (r'\mathbb{gamma}', '\u213D'), 78 | (r'\fallingdotseq', '\u2252'), 79 | (r'\looparrowleft', '\u21AB'), 80 | (r'\textbrokenbar', '\u00A6'), 81 | (r'\hookleftarrow', '\u21A9'), 82 | (r'\smallsetminus', '\uFE68'), 83 | (r'\dashleftarrow', '\u21E0'), 84 | (r'\guillemotleft', '\u00AB'), 85 | (r'\leftharpoonup', '\u21BC'), 86 | (r'\mathbb{Gamma}', '\u213E'), 87 | (r'\bigtriangleup', '\u25B3'), 88 | (r'\textcircledP', '\u2117'), 89 | (r'\risingdotseq', '\u2253'), 90 | (r'\triangleleft', '\u25C3'), 91 | (r'\mathsterling', '\u00A3'), 92 | (r'\textcurrency', '\u00A4'), 93 | (r'\triangledown', '\u25BF'), 94 | (r'\blacklozenge', '\uE80B'), 95 | (r'\sfrac{5}{6}', '\u215A'), 96 | (r'\preccurlyeq', '\u227C'), 97 | (r'\Rrightarrow', '\u21DB'), 98 | (r'\circledcirc', '\u229A'), 99 | (r'\nRightarrow', '\u21CF'), 100 | (r'\sfrac{3}{8}', '\u215C'), 101 | (r'\sfrac{1}{3}', '\u2153'), 102 | (r'\sfrac{2}{5}', '\u2156'), 103 | (r'\vartriangle', '\u25B5'), 104 | (r'\Updownarrow', '\u21D5'), 105 | (r'\nrightarrow', '\u219B'), 106 | (r'\sfrac{1}{2}', '\u00BD'), 107 | (r'\sfrac{3}{5}', '\u2157'), 108 | (r'\succcurlyeq', '\u227D'), 109 | (r'\sfrac{4}{5}', '\u2158'), 110 | (r'\diamondsuit', '\u2666'), 111 | (r'\hphantom{0}', '\u2007'), 112 | (r'\sfrac{1}{6}', '\u2159'), 113 | (r'\curlyeqsucc', '\u22DF'), 114 | (r'\blacksquare', '\u25AA'), 115 | (r'\hphantom{,}', '\u2008'), 116 | (r'\curlyeqprec', '\u22DE'), 117 | (r'\sfrac{1}{8}', '\u215B'), 118 | (r'\sfrac{7}{8}', '\u215E'), 119 | (r'\sfrac{1}{5}', '\u2155'), 120 | (r'\sfrac{2}{3}', '\u2154'), 121 | (r'\updownarrow', '\u2195'), 122 | (r'\backepsilon', '\u220D'), 123 | (r'\circleddash', '\u229D'), 124 | (r'\eqslantless', '\u22DC'), 125 | (r'\sfrac{3}{4}', '\u00BE'), 126 | (r'\sfrac{5}{8}', '\u215D'), 127 | (r'\hspace{1pt}', '\u200A'), 128 | (r'\sfrac{1}{4}', '\u00BC'), 129 | (r'\mathbb{Pi}', '\u213F'), 130 | (r'\mathcal{M}', '\u2133'), 131 | (r'\mathcal{o}', '\U00002134'), 132 | (r'\mathcal{O}', '\U0001d4aA'), 133 | (r'\nsupseteqq', '\u2289'), 134 | (r'\mathcal{B}', '\u212C'), 135 | (r'\textrecipe', '\u211E'), 136 | (r'\nsubseteqq', '\u2288'), 137 | (r'\subsetneqq', '\u228A'), 138 | (r'\mathcal{I}', '\u2111'), 139 | (r'\upuparrows', '\u21C8'), 140 | (r'\mathcal{e}', '\u212F'), 141 | (r'\mathcal{L}', '\u2112'), 142 | (r'\nleftarrow', '\u219A'), 143 | (r'\mathcal{H}', '\u210B'), 144 | (r'\mathcal{E}', '\u2130'), 145 | (r'\eqslantgtr', '\u22DD'), 146 | (r'\curlywedge', '\u22CF'), 147 | (r'\varepsilon', '\u03B5'), 148 | (r'\supsetneqq', '\u228B'), 149 | (r'\rightarrow', '\u2192'), 150 | (r'\mathcal{R}', '\u211B'), 151 | (r'\sqsubseteq', '\u2291'), 152 | (r'\mathcal{g}', '\u210A'), 153 | (r'\sqsupseteq', '\u2292'), 154 | (r'\complement', '\u2201'), 155 | (r'\Rightarrow', '\u21D2'), 156 | (r'\gtreqqless', '\u22DB'), 157 | (r'\lesseqqgtr', '\u22DA'), 158 | (r'\circledast', '\u229B'), 159 | (r'\nLeftarrow', '\u21CD'), 160 | (r'\Lleftarrow', '\u21DA'), 161 | (r'\Leftarrow', '\u21D0'), 162 | (r'\gvertneqq', '\u2269'), 163 | (r'\mathbb{C}', '\u2102'), 164 | (r'\supsetneq', '\u228B'), 165 | (r'\leftarrow', '\u2190'), 166 | (r'\nleqslant', '\u2270'), 167 | (r'\mathbb{Q}', '\u211A'), 168 | (r'\mathbb{Z}', '\u2124'), 169 | (r'\llbracket', '\u301A'), 170 | (r'\mathbb{H}', '\u210D'), 171 | (r'\spadesuit', '\u2660'), 172 | (r'\mathit{o}', '\U0001d45c'), 173 | (r'\mathbb{P}', '\u2119'), 174 | (r'\rrbracket', '\u301B'), 175 | (r'\supseteqq', '\u2287'), 176 | (r'\copyright', '\u00A9'), 177 | (r'\textsc{k}', '\u0138'), 178 | (r'\gtreqless', '\u22DB'), 179 | (r'\mathbb{j}', '\u2149'), 180 | (r'\pitchfork', '\u22D4'), 181 | (r'\estimated', '\u212E'), 182 | (r'\ngeqslant', '\u2271'), 183 | (r'\mathbb{e}', '\u2147'), 184 | (r'\therefore', '\u2234'), 185 | (r'\triangleq', '\u225C'), 186 | (r'\varpropto', '\u221D'), 187 | (r'\subsetneq', '\u228A'), 188 | (r'\heartsuit', '\u2665'), 189 | (r'\mathbb{d}', '\u2146'), 190 | (r'\lvertneqq', '\u2268'), 191 | (r'\checkmark', '\u2713'), 192 | (r'\nparallel', '\u2226'), 193 | (r'\mathbb{R}', '\u211D'), 194 | (r'\lesseqgtr', '\u22DA'), 195 | (r'\downarrow', '\u2193'), 196 | (r'\mathbb{D}', '\u2145'), 197 | (r'\mathbb{i}', '\u2148'), 198 | (r'\backsimeq', '\u22CD'), 199 | (r'\mathbb{N}', '\u2115'), 200 | (r'\Downarrow', '\u21D3'), 201 | (r'\subseteqq', '\u2286'), 202 | (r'\setminus', '\u2216'), 203 | (r'\succnsim', '\u22E9'), 204 | (r'\doteqdot', '\u2251'), 205 | (r'\clubsuit', '\u2663'), 206 | (r'\emptyset', '\u2205'), 207 | (r'\varnothing', '\u2205'), 208 | (r'\sqsupset', '\u2290'), 209 | (r'\fbox{~~}', '\u25AD'), 210 | (r'\curlyvee', '\u22CE'), 211 | (r'\varkappa', '\u03F0'), 212 | (r'\llcorner', '\u231E'), 213 | (r'\varsigma', '\u03C2'), 214 | (r'\approxeq', '\u224A'), 215 | (r'\backcong', '\u224C'), 216 | (r'\supseteq', '\u2287'), 217 | (r'\circledS', '\u24C8'), 218 | (r'\circledR', '\u00AE'), 219 | (r'\textcent', '\u00A2'), 220 | (r'\urcorner', '\u231D'), 221 | (r'\lrcorner', '\u231F'), 222 | (r'\boxminus', '\u229F'), 223 | (r'\texteuro', '\u20AC'), 224 | (r'\vartheta', '\u03D1'), 225 | (r'\barwedge', '\u22BC'), 226 | (r'\ding{86}', '\u2736'), 227 | (r'\sqsubset', '\u228F'), 228 | (r'\subseteq', '\u2286'), 229 | (r'\intercal', '\u22BA'), 230 | (r'\ding{73}', '\u2606'), 231 | (r'\ulcorner', '\u231C'), 232 | (r'\recorder', '\u2315'), 233 | (r'\precnsim', '\u22E8'), 234 | (r'\parallel', '\u2225'), 235 | (r'\boxtimes', '\u22A0'), 236 | (r'\ding{55}', '\u2717'), 237 | (r'\multimap', '\u22B8'), 238 | (r'\maltese', '\u2720'), 239 | (r'\nearrow', '\u2197'), 240 | (r'\swarrow', '\u2199'), 241 | (r'\lozenge', '\u25CA'), 242 | (r'\sqrt[3]', '\u221B'), 243 | (r'\succsim', '\u227F'), 244 | # (r'\tilde{}', '\u007E'), 245 | (r'\lessgtr', '\u2276'), 246 | (r'\Upsilon', '\u03D2'), 247 | (r'\Cdprime', '\u042A'), 248 | (r'\gtrless', '\u2277'), 249 | (r'\backsim', '\u223D'), 250 | (r'\nexists', '\u2204'), 251 | (r'\dotplus', '\u2214'), 252 | (r'\searrow', '\u2198'), 253 | (r'\lessdot', '\u22D6'), 254 | (r'\boxplus', '\u229E'), 255 | (r'\upsilon', '\u03C5'), 256 | (r'\epsilon', '\u03B5'), 257 | (r'\diamond', '\u22C4'), 258 | (r'\bigstar', '\u2605'), 259 | (r'\ddagger', '\u2021'), 260 | (r'\cdprime', '\u044A'), 261 | (r'\Uparrow', '\u21D1'), 262 | (r'\sqrt[4]', '\u221C'), 263 | (r'\between', '\u226C'), 264 | (r'\sqangle', '\u221F'), 265 | (r'\digamma', '\u03DC'), 266 | (r'\uparrow', '\u2191'), 267 | (r'\nwarrow', '\u2196'), 268 | (r'\precsim', '\u227E'), 269 | (r'\breve{}', '\u02D8'), 270 | (r'\because', '\u2235'), 271 | (r'\bigcirc', '\u25EF'), 272 | (r'\acute{}', '\u00B4'), 273 | (r'\grave{}', '\u0060'), 274 | (r'\check{}', '\u02C7'), 275 | (r'\lesssim', '\u2272'), 276 | (r'\partial', '\u2202'), 277 | (r'\natural', '\u266E'), 278 | (r'\supset', '\u2283'), 279 | (r'\hstrok', '\u0127'), 280 | (r'\Tstrok', '\u0166'), 281 | (r'\coprod', '\u2210'), 282 | (r'\models', '\u22A7'), 283 | (r'\otimes', '\u2297'), 284 | (r'\degree', '\u00B0'), 285 | (r'\gtrdot', '\u22D7'), 286 | (r'\preceq', '\u227C'), 287 | (r'\Lambda', '\u039B'), 288 | (r'\lambda', '\u03BB'), 289 | (r'\cprime', '\u044C'), 290 | (r'\varrho', '\u03F1'), 291 | (r'\Bumpeq', '\u224E'), 292 | (r'\hybull', '\u2043'), 293 | (r'\lmidot', '\u0140'), 294 | (r'\nvdash', '\u22AC'), 295 | (r'\lbrace', '\u007B'), 296 | (r'\bullet', '\u2022'), 297 | (r'\varphi', '\u03C6'), 298 | (r'\bumpeq', '\u224F'), 299 | (r'\ddot{}', '\u00A8'), 300 | (r'\Lmidot', '\u013F'), 301 | (r'\Cprime', '\u042C'), 302 | (r'\female', '\u2640'), 303 | (r'\rtimes', '\u22CA'), 304 | (r'\gtrsim', '\u2273'), 305 | (r'\mapsto', '\u21A6'), 306 | (r'\daleth', '\u2138'), 307 | (r'\square', '\u25A0'), 308 | (r'\nVDash', '\u22AF'), 309 | (r'\rangle', '\u3009'), 310 | (r'\tstrok', '\u0167'), 311 | (r'\oslash', '\u2298'), 312 | (r'\ltimes', '\u22C9'), 313 | (r'\lfloor', '\u230A'), 314 | (r'\marker', '\u25AE'), 315 | (r'\Subset', '\u22D0'), 316 | (r'\Vvdash', '\u22AA'), 317 | (r'\propto', '\u221D'), 318 | (r'\Hstrok', '\u0126'), 319 | (r'\dlcrop', '\u230D'), 320 | (r'\forall', '\u2200'), 321 | (r'\nVdash', '\u22AE'), 322 | (r'\Supset', '\u22D1'), 323 | (r'\langle', '\u3008'), 324 | (r'\ominus', '\u2296'), 325 | (r'\rfloor', '\u230B'), 326 | (r'\circeq', '\u2257'), 327 | (r'\eqcirc', '\u2256'), 328 | (r'\drcrop', '\u230C'), 329 | (r'\veebar', '\u22BB'), 330 | (r'\ulcrop', '\u230F'), 331 | (r'\nvDash', '\u22AD'), 332 | (r'\urcrop', '\u230E'), 333 | (r'\exists', '\u2203'), 334 | (r'\approx', '\u2248'), 335 | (r'\dagger', '\u2020'), 336 | (r'\boxdot', '\u22A1'), 337 | (r'\succeq', '\u227D'), 338 | (r'\bowtie', '\u22C8'), 339 | (r'\subset', '\u2282'), 340 | (r'\Sigma', '\u03A3'), 341 | (r'\Omega', '\u03A9'), 342 | (r'\nabla', '\u2207'), 343 | (r'\colon', '\u003A'), 344 | (r'\boxHu', '\u2567'), 345 | (r'\boxHd', '\u2564'), 346 | (r'\aleph', '\u2135'), 347 | (r'\gnsim', '\u22E7'), 348 | (r'\boxHU', '\u2569'), 349 | (r'\boxHD', '\u2566'), 350 | (r'\equiv', '\u2261'), 351 | (r'\lneqq', '\u2268'), 352 | (r'\alpha', '\u03B1'), 353 | (r'\amalg', '\u2210'), 354 | (r'\boxhU', '\u2568'), 355 | (r'\boxhD', '\u2565'), 356 | (r'\uplus', '\u228E'), 357 | (r'\boxhu', '\u2534'), 358 | (r'\kappa', '\u03BA'), 359 | (r'\sigma', '\u03C3'), 360 | (r'\boxDL', '\u2557'), 361 | (r'\Theta', '\u0398'), 362 | (r'\Vdash', '\u22A9'), 363 | (r'\boxDR', '\u2554'), 364 | (r'\boxDl', '\u2556'), 365 | (r'\sqcap', '\u2293'), 366 | (r'\boxDr', '\u2553'), 367 | (r'\bar{}', '\u00AF'), 368 | (r'\dashv', '\u22A3'), 369 | (r'\vDash', '\u22A8'), 370 | (r'\boxdl', '\u2510'), 371 | (r'\boxVl', '\u2562'), 372 | (r'\boxVh', '\u256B'), 373 | (r'\boxVr', '\u255F'), 374 | (r'\boxdr', '\u250C'), 375 | (r'\boxdL', '\u2555'), 376 | (r'\boxVL', '\u2563'), 377 | (r'\boxVH', '\u256C'), 378 | (r'\boxVR', '\u2560'), 379 | (r'\boxdR', '\u2552'), 380 | (r'\theta', '\u03B8'), 381 | (r'\lhblk', '\u2584'), 382 | (r'\uhblk', '\u2580'), 383 | (r'\ldotp', '\u002E'), 384 | (r'\ldots', '\u2026'), 385 | (r'\boxvL', '\u2561'), 386 | (r'\boxvH', '\u256A'), 387 | (r'\boxvR', '\u255E'), 388 | (r'\boxvl', '\u2524'), 389 | (r'\boxvh', '\u253C'), 390 | (r'\boxvr', '\u251C'), 391 | (r'\Delta', '\u0394'), 392 | (r'\boxUR', '\u255A'), 393 | (r'\boxUL', '\u255D'), 394 | (r'\oplus', '\u2295'), 395 | (r'\boxUr', '\u2559'), 396 | (r'\boxUl', '\u255C'), 397 | (r'\doteq', '\u2250'), 398 | (r'\happy', '\u32E1'), 399 | (r'\varpi', '\u03D6'), 400 | (r'\boxr', '\u2514'), 401 | (r'\smile', '\u263A'), 402 | (r'\boxul', '\u2518'), 403 | (r'\simeq', '\u2243'), 404 | (r'\boxuR', '\u2558'), 405 | (r'\boxuL', '\u255B'), 406 | (r'\boxhd', '\u252C'), 407 | (r'\gimel', '\u2137'), 408 | (r'\Gamma', '\u0393'), 409 | (r'\lnsim', '\u22E6'), 410 | (r'\sqcup', '\u2294'), 411 | (r'\omega', '\u03C9'), 412 | (r'\sharp', '\u266F'), 413 | (r'\times', '\u00D7'), 414 | (r'\block', '\u2588'), 415 | (r'\hat{}', '\u005E'), 416 | (r'\wedge', '\u2227'), 417 | (r'\vdash', '\u22A2'), 418 | (r'\angle', '\u2220'), 419 | (r'\infty', '\u221E'), 420 | (r'\gamma', '\u03B3'), 421 | (r'\asymp', '\u224D'), 422 | (r'\rceil', '\u2309'), 423 | (r'\dot{}', '\u02D9'), 424 | (r'\lceil', '\u2308'), 425 | (r'\delta', '\u03B4'), 426 | (r'\gneqq', '\u2269'), 427 | (r'\frown', '\u2322'), 428 | (r'\phone', '\u260E'), 429 | (r'\vdots', '\u22EE'), 430 | (r'\k{i}', '\u012F'), 431 | (r'\`{I}', '\u00CC'), 432 | (r'\perp', '\u22A5'), 433 | (r'\"{o}', '\u00F6'), 434 | (r'\={I}', '\u012A'), 435 | (r'\`{a}', '\u00E0'), 436 | (r'\v{T}', '\u0164'), 437 | (r'\surd', '\u221A'), 438 | (r'\H{O}', '\u0150'), 439 | (r'\vert', '\u007C'), 440 | (r'\k{I}', '\u012E'), 441 | (r'\"{y}', '\u00FF'), 442 | (r'\"{O}', '\u00D6'), 443 | (r'\'{Y}', '\u00DD'), 444 | (r'\u{u}', '\u045E'), 445 | (r'\u{G}', '\u011E'), 446 | (r'\.{E}', '\u0116'), 447 | (r'\.{z}', '\u017C'), 448 | (r'\v{t}', '\u0165'), 449 | (r'\prec', '\u227A'), 450 | (r'\H{o}', '\u0151'), 451 | (r'\mldr', '\u2026'), 452 | (r'\'{y}', '\u00FD'), 453 | (r'\cong', '\u2245'), 454 | (r'\.{e}', '\u0117'), 455 | (r'\'{L}', '\u0139'), 456 | (r'\star', '\u002A'), 457 | (r'\.{Z}', '\u017B'), 458 | (r'\'{e}', '\u00E9'), 459 | (r'\geqq', '\u2267'), 460 | (r'\cdot', '\u22C5'), 461 | (r'\`{U}', '\u00D9'), 462 | (r'\'{l}', '\u013A'), 463 | (r'\v{L}', '\u013D'), 464 | (r'\c{s}', '\u015F'), 465 | (r'\'{s}', '\u015B'), 466 | (r'\~{A}', '\u00C3'), 467 | (r'\Vert', '\u2016'), 468 | (r'\k{e}', '\u0119'), 469 | (r'\lnot', '\u00AC'), 470 | (r'\'{z}', '\u017A'), 471 | (r'\leqq', '\u2266'), 472 | (r'\beta', '\u03B2'), 473 | (r'\beth', '\u2136'), 474 | (r'\'{E}', '\u00C9'), 475 | (r'\~{n}', '\u00F1'), 476 | (r'\u{i}', '\u0439'), 477 | (r'\c{S}', '\u015E'), 478 | (r'\c{N}', '\u0145'), 479 | (r'\H{u}', '\u0171'), 480 | (r'\v{n}', '\u0148'), 481 | (r'\'{S}', '\u015A'), 482 | (r'\={U}', '\u016A'), 483 | (r'\~{O}', '\u00D5'), 484 | (r'\'{Z}', '\u0179'), 485 | (r'\v{E}', '\u011A'), 486 | (r'\'{R}', '\u0154'), 487 | (r'\H{U}', '\u0170'), 488 | (r'\v{N}', '\u0147'), 489 | (r'\prod', '\u220F'), 490 | (r'\v{s}', '\u0161'), 491 | (r'\"{U}', '\u00DC'), 492 | (r'\c{n}', '\u0146'), 493 | (r'\k{U}', '\u0172'), 494 | (r'\c{R}', '\u0156'), 495 | (r'\'{A}', '\u00C1'), 496 | (r'\~{o}', '\u00F5'), 497 | (r'\v{e}', '\u011B'), 498 | (r'\v{S}', '\u0160'), 499 | (r'\u{A}', '\u0102'), 500 | (r'\circ', '\u2218'), 501 | (r'\"{u}', '\u00FC'), 502 | (r'\flat', '\u266D'), 503 | (r'\v{z}', '\u017E'), 504 | (r'\r{U}', '\u016E'), 505 | (r'\`{O}', '\u00D2'), 506 | (r'\={u}', '\u016B'), 507 | (r'\oint', '\u222E'), 508 | (r'\c{K}', '\u0136'), 509 | (r'\k{u}', '\u0173'), 510 | (r'\not<', '\u226E'), 511 | (r'\not>', '\u226F'), 512 | (r'\`{o}', '\u00F2'), 513 | (r'\"{I}', '\u00CF'), 514 | (r'\v{D}', '\u010E'), 515 | (r'\.{G}', '\u0120'), 516 | (r'\r{u}', '\u016F'), 517 | (r'\not=', '\u2260'), 518 | (r'\`{u}', '\u00F9'), 519 | (r'\v{c}', '\u010D'), 520 | (r'\c{k}', '\u0137'), 521 | (r'\.{g}', '\u0121'), 522 | (r'\'{N}', '\u0143'), 523 | (r'\odot', '\u2299'), 524 | (r'\`{e}', '\u044D'), 525 | (r'\c{T}', '\u0162'), 526 | (r'\v{d}', '\u010F'), 527 | (r'\"{e}', '\u0451'), 528 | (r'\'{I}', '\u00CD'), 529 | (r'\v{R}', '\u0158'), 530 | (r'\k{a}', '\u0105'), 531 | (r'\nldr', '\u2025'), 532 | (r'\`{A}', '\u00C0'), 533 | (r'\'{n}', '\u0144'), 534 | (r'\~{N}', '\u00D1'), 535 | (r'\nmid', '\u2224'), 536 | (r'\.{C}', '\u010A'), 537 | (r'\zeta', '\u03B6'), 538 | (r'\~{u}', '\u0169'), 539 | (r'\`{E}', '\u042D'), 540 | (r'\~{a}', '\u00E3'), 541 | (r'\c{t}', '\u0163'), 542 | (r'\={o}', '\u014D'), 543 | (r'\v{r}', '\u0159'), 544 | (r'\={A}', '\u0100'), 545 | (r'\.{c}', '\u010B'), 546 | (r'\~{U}', '\u0168'), 547 | (r'\k{A}', '\u0104'), 548 | (r'\"{a}', '\u00E4'), 549 | (r'\u{U}', '\u040E'), 550 | (r'\iota', '\u03B9'), 551 | (r'\={O}', '\u014C'), 552 | (r'\c{C}', '\u00C7'), 553 | (r'\gneq', '\u2269'), 554 | (r'\'{c}', '\u0107'), 555 | (r'\boxH', '\u2550'), 556 | (r'\hbar', '\u210F'), 557 | (r'\"{A}', '\u00C4'), 558 | (r'\boxv', '\u2502'), 559 | (r'\boxh', '\u2500'), 560 | (r'\male', '\u2642'), 561 | (r'\'{u}', '\u00FA'), 562 | (r'\sqrt', '\u221A'), 563 | (r'\succ', '\u227B'), 564 | (r'\c{c}', '\u00E7'), 565 | (r'\'{C}', '\u0106'), 566 | (r'\v{l}', '\u013E'), 567 | (r'\u{a}', '\u0103'), 568 | (r'\v{Z}', '\u017D'), 569 | (r'\'{o}', '\u00F3'), 570 | (r'\c{G}', '\u0122'), 571 | (r'\v{C}', '\u010C'), 572 | (r'\lneq', '\u2268'), 573 | (r'\"{E}', '\u0401'), 574 | (r'\={a}', '\u0101'), 575 | (r'\c{l}', '\u013C'), 576 | (r'\'{a}', '\u00E1'), 577 | (r'\={E}', '\u0112'), 578 | (r'\boxV', '\u2551'), 579 | (r'\u{g}', '\u011F'), 580 | (r'\'{O}', '\u00D3'), 581 | (r'\'{g}', '\u01F5'), 582 | (r'\u{I}', '\u0419'), 583 | (r'\c{L}', '\u013B'), 584 | (r'\k{E}', '\u0118'), 585 | (r'\.{I}', '\u0130'), 586 | (r'\~{I}', '\u0128'), 587 | (r'\quad', '\u2003'), 588 | (r'\c{r}', '\u0157'), 589 | (r'\'{r}', '\u0155'), 590 | (r'\"{Y}', '\u0178'), 591 | (r'\={e}', '\u0113'), 592 | (r'\'{U}', '\u00DA'), 593 | (r'\leq', '\u2264'), 594 | (r'\Cup', '\u22D3'), 595 | (r'\Psi', '\u03A8'), 596 | (r'\neq', '\u2260'), 597 | (r'\k{}', '\u02DB'), 598 | (r'\={}', '\u203E'), 599 | (r'\H{}', '\u02DD'), 600 | (r'\cup', '\u222A'), 601 | (r'\geq', '\u2265'), 602 | (r'\mho', '\u2127'), 603 | (r'\Dzh', '\u040F'), 604 | (r'\cap', '\u2229'), 605 | (r'\bot', '\u22A5'), 606 | (r'\psi', '\u03C8'), 607 | (r'\chi', '\u03C7'), 608 | (r'\c{}', '\u00B8'), 609 | (r'\Phi', '\u03A6'), 610 | (r'\ast', '\u002A'), 611 | (r'\ell', '\u2113'), 612 | (r'\top', '\u22A4'), 613 | (r'\lll', '\u22D8'), 614 | (r'\tau', '\u03C4'), 615 | (r'\Cap', '\u22D2'), 616 | (r'\sad', '\u2639'), 617 | (r'\iff', '\u21D4'), 618 | (r'\eta', '\u03B7'), 619 | (r'\eth', '\u00F0'), 620 | (r'\d{}', '\u0323'), 621 | (r'\rho', '\u03C1'), 622 | (r'\dzh', '\u045F'), 623 | (r'\div', '\u00F7'), 624 | (r'\phi', '\u03D5'), 625 | (r'\Rsh', '\u21B1'), 626 | (r'\vee', '\u2228'), 627 | (r'\b{}', '\u02CD'), 628 | (r'\t{}', '\u0361'), 629 | (r'\int', '\u222B'), 630 | (r'\sim', '\u223C'), 631 | (r'\r{}', '\u02DA'), 632 | (r'\Lsh', '\u21B0'), 633 | (r'\yen', '\u00A5'), 634 | (r'\ggg', '\u22D9'), 635 | (r'\mid', '\u2223'), 636 | (r'\sum', '\u2211'), 637 | (r'\Dz', '\u0405'), 638 | (r'\Re', '\u211C'), 639 | (r'\oe', '\u0153'), 640 | (r'\DH', '\u00D0'), 641 | (r'\ll', '\u226A'), 642 | (r'\ng', '\u014B'), 643 | (r'\'G', '\u0403'), 644 | (r'\wr', '\u2240'), 645 | (r'\wp', '\u2118'), 646 | (r'\=I', '\u0406'), 647 | (r'\:)', '\u263A'), 648 | (r'\:(', '\u2639'), 649 | (r'\AE', '\u00C6'), 650 | (r'\AA', '\u00C5'), 651 | (r'\ss', '\u00DF'), 652 | (r'\dz', '\u0455'), 653 | (r'\ae', '\u00E6'), 654 | (r'\aa', '\u00E5'), 655 | (r'\th', '\u00FE'), 656 | (r'\to', '\u2192'), 657 | (r'\Pi', '\u03A0'), 658 | (r'\mp', '\u2213'), 659 | (r'\Im', '\u2111'), 660 | (r'\pm', '\u00B1'), 661 | (r'\pi', '\u03C0'), 662 | (r'\"I', '\u0407'), 663 | (r'\'C', '\u040B'), 664 | (r'\in', '\u2208'), 665 | (r'\'K', '\u040C'), 666 | (r'\'k', '\u045C'), 667 | (r'\'c', '\u045B'), 668 | (r'\'g', '\u0453'), 669 | (r'\ni', '\u220B'), 670 | (r'\ne', '\u2260'), 671 | (r'\TH', '\u00DE'), 672 | (r'\Xi', '\u039E'), 673 | (r'\nu', '\u03BD'), 674 | (r'\NG', '\u014A'), 675 | (r'\:G', '\u32E1'), 676 | (r'\xi', '\u03BE'), 677 | (r'\OE', '\u0152'), 678 | (r'\gg', '\u226B'), 679 | (r'\DJ', '\u0110'), 680 | (r'\=e', '\u0454'), 681 | (r'\=E', '\u0404'), 682 | (r'\mu', '\u03BC'), 683 | (r'\dj', '\u0111'), 684 | # (r'\:', '\u2004'), 685 | # (r'\;', '\u2002'), 686 | (r'\&', '\u0026'), 687 | (r'\$', '\u0024'), 688 | (r'\%', '\u0025'), 689 | (r'\#', '\u0023'), 690 | (r'\,', '\u2009'), 691 | (r'\-', '\u00AD'), 692 | (r'\S', '\u00A7'), 693 | (r'\P', '\u00B6'), 694 | (r'\O', '\u00D8'), 695 | (r'\L', '\u0141'), 696 | (r'\}', '\u007D'), 697 | (r'\o', '\u00F8'), 698 | (r'\l', '\u0142'), 699 | (r'\h', '\u210E'), 700 | (r'\i', '\u2139'), 701 | ] 702 | COMBININGMARKS_V06 = [ 703 | (r'\tilde', '\u0303'), 704 | (r'\grave', '\u0300'), 705 | (r'\dot', '\u0307'), 706 | (r'\acute', '\u0301'), 707 | (r'\doubleunderline', '\u0333'), 708 | (r'\ddot', '\u0308'), 709 | (r'\slash', '\u0338'), 710 | (r'\overline', '\u0305'), 711 | (r'\vec', '\u20D7'), 712 | (r'\hat', '\u0302'), 713 | (r'\breve', '\u0306'), 714 | (r'\underline', '\u0332'), 715 | (r'\strikethrough', '\u0335'), 716 | (r'\bar', '\u0305'), 717 | ] 718 | SUBSUPERSCRIPTS_V06 = [ 719 | (r'_x', '\u2093'), 720 | (r'_v', '\u1D65'), 721 | (r'_u', '\u1D64'), 722 | (r'_t', '\u209C'), 723 | (r'_s', '\u209B'), 724 | (r'_r', '\u1D63'), 725 | (r'_p', '\u209A'), 726 | (r'_o', '\u2092'), 727 | (r'_n', '\u2099'), 728 | (r'_m', '\u2098'), 729 | (r'_l', '\u2097'), 730 | (r'_k', '\u2096'), 731 | (r'_j', '\u2C7C'), 732 | (r'_i', '\u1D62'), 733 | (r'_h', '\u2095'), 734 | (r'_e', '\u2091'), 735 | (r'_a', '\u2090'), 736 | # (r'\^\u222B', '\u1DB4'), 737 | (r'_>', '\u02F2'), 738 | (r'_=', '\u208C'), 739 | (r'_<', '\u02F1'), 740 | (r'_9', '\u2089'), 741 | (r'_8', '\u2088'), 742 | (r'_7', '\u2087'), 743 | (r'_6', '\u2086'), 744 | (r'_5', '\u2085'), 745 | (r'_4', '\u2084'), 746 | (r'_3', '\u2083'), 747 | (r'_2', '\u2082'), 748 | (r'_1', '\u2081'), 749 | (r'_0', '\u2080'), 750 | (r'_-', '\u208B'), 751 | (r'_+', '\u208A'), 752 | (r'_)', '\u208E'), 753 | (r'_(', '\u208D'), 754 | # (r'_\u03C1', '\u1D68'), 755 | # (r'_\u03C7', '\u1D6A'), 756 | # (r'_\u03C6', '\u1D69'), 757 | # (r'_\u03B2', '\u1D66'), 758 | # (r'_\u03B3', '\u1D67'), 759 | # (r'\^\u03C6', '\u1D60'), 760 | # (r'\^\u03C7', '\u1D61'), 761 | # (r'\^\u03B4', '\u1D5F'), 762 | # (r'\^\u03B3', '\u1D5E'), 763 | # (r'\^\u03B2', '\u1D5D'), 764 | (r'^8', '\u2078'), 765 | (r'^9', '\u2079'), 766 | (r'^<', '\u02C2'), 767 | (r'^=', '\u207C'), 768 | (r'^>', '\u02C3'), 769 | (r'^0', '\u2070'), 770 | (r'^1', '\u00B9'), 771 | (r'^2', '\u00B2'), 772 | (r'^3', '\u00B3'), 773 | (r'^4', '\u2074'), 774 | (r'^5', '\u2075'), 775 | (r'^6', '\u2076'), 776 | (r'^7', '\u2077'), 777 | (r'^(', '\u207D'), 778 | (r'^)', '\u207E'), 779 | (r'^*', '\u002A'), 780 | (r'^+', '\u207A'), 781 | (r'^-', '\u207B'), 782 | (r'^P', '\u1D3E'), 783 | (r'^R', '\u1D3F'), 784 | (r'^T', '\u1D40'), 785 | (r'^U', '\u1D41'), 786 | (r'^V', '\u1111'), 787 | (r'^W', '\u1D42'), 788 | (r'^H', '\u1D34'), 789 | (r'^I', '\u1D35'), 790 | (r'^J', '\u1D36'), 791 | (r'^K', '\u1D37'), 792 | (r'^L', '\u1D38'), 793 | (r'^M', '\u1D39'), 794 | (r'^N', '\u1D3A'), 795 | (r'^O', '\u1D3C'), 796 | (r'^A', '\u1D2C'), 797 | (r'^B', '\u1D2E'), 798 | (r'^D', '\u1D30'), 799 | (r'^E', '\u1D31'), 800 | (r'^G', '\u1D33'), 801 | (r'^x', '\u02E3'), 802 | (r'^y', '\u02B8'), 803 | (r'^z', '\u1DBB'), 804 | (r'^p', '\u1D56'), 805 | (r'^r', '\u02B3'), 806 | (r'^s', '\u02E2'), 807 | (r'^t', '\u1D57'), 808 | (r'^u', '\u1D58'), 809 | (r'^v', '\u1D5B'), 810 | (r'^w', '\u02B7'), 811 | (r'^h', '\u02B0'), 812 | (r'^i', '\u2071'), 813 | (r'^j', '\u02B2'), 814 | (r'^k', '\u1D4F'), 815 | (r'^l', '\u02E1'), 816 | (r'^m', '\u1D50'), 817 | (r'^n', '\u207F'), 818 | (r'^o', '\u1D52'), 819 | (r'^a', '\u1D43'), 820 | (r'^b', '\u1D47'), 821 | (r'^c', '\u1D9C'), 822 | (r'^d', '\u1D48'), 823 | (r'^e', '\u1D49'), 824 | (r'^f', '\u1DA0'), 825 | (r'^g', '\u1D4D'), 826 | ] 827 | 828 | 829 | @pytest.mark.parametrize('sets_of_symbols', [SYMBOLS_V06, SUBSUPERSCRIPTS_V06]) 830 | def test_symbols_v06(sets_of_symbols): 831 | for i in range(0, len(sets_of_symbols), 20): 832 | symbols = sets_of_symbols[i:i + 20] 833 | latex = ''.join([l for l, _ in symbols]) 834 | unicode = ''.join([u for _, u in symbols]) 835 | print(latex) 836 | 837 | r = subprocess.check_output([ 838 | PYTHON, '-m', 'unicodeit.cli', 839 | latex, 840 | ]) 841 | print(r.decode()) 842 | assert r.decode().strip() == unicode.strip() 843 | 844 | 845 | def test_combiningmarks_v06(): 846 | for i in range(0, len(COMBININGMARKS_V06), 20): 847 | symbols = COMBININGMARKS_V06[i:i + 20] 848 | latex = ''.join([l + '{a}' for l, _ in symbols]) 849 | unicode = ''.join(['a' + u for _, u in symbols]) 850 | print(latex) 851 | 852 | r = subprocess.check_output([ 853 | PYTHON, '-m', 'unicodeit.cli', 854 | latex, 855 | ]) 856 | print(r.decode()) 857 | assert r.decode().strip() == unicode 858 | 859 | 860 | def test_combiningmarks_v06_nested_replace(): 861 | for i in range(0, len(COMBININGMARKS_V06), 20): 862 | symbols = COMBININGMARKS_V06[i:i + 20] 863 | latex = ''.join([l + '{\\alpha}' for l, _ in symbols]) 864 | unicode = ''.join(['\u03B1' + u for _, u in symbols]) 865 | print(latex) 866 | 867 | r = subprocess.check_output([ 868 | PYTHON, '-m', 'unicodeit.cli', 869 | latex, 870 | ]) 871 | print(r.decode()) 872 | assert r.decode().strip() == unicode 873 | -------------------------------------------------------------------------------- /web/typeahead.bundle.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * typeahead.js 0.11.1 3 | * https://github.com/twitter/typeahead.js 4 | * Copyright 2013-2015 Twitter, Inc. and other contributors; Licensed MIT 5 | */ 6 | 7 | !function(a,b){"function"==typeof define&&define.amd?define("bloodhound",["jquery"],function(c){return a.Bloodhound=b(c)}):"object"==typeof exports?module.exports=b(require("jquery")):a.Bloodhound=b(jQuery)}(this,function(a){var b=function(){"use strict";return{isMsie:function(){return/(msie|trident)/i.test(navigator.userAgent)?navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2]:!1},isBlankString:function(a){return!a||/^\s*$/.test(a)},escapeRegExChars:function(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},isString:function(a){return"string"==typeof a},isNumber:function(a){return"number"==typeof a},isArray:a.isArray,isFunction:a.isFunction,isObject:a.isPlainObject,isUndefined:function(a){return"undefined"==typeof a},isElement:function(a){return!(!a||1!==a.nodeType)},isJQuery:function(b){return b instanceof a},toStr:function(a){return b.isUndefined(a)||null===a?"":a+""},bind:a.proxy,each:function(b,c){function d(a,b){return c(b,a)}a.each(b,d)},map:a.map,filter:a.grep,every:function(b,c){var d=!0;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?void 0:!1}),!!d):d},some:function(b,c){var d=!1;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?!1:void 0}),!!d):d},mixin:a.extend,identity:function(a){return a},clone:function(b){return a.extend(!0,{},b)},getIdGenerator:function(){var a=0;return function(){return a++}},templatify:function(b){function c(){return String(b)}return a.isFunction(b)?b:c},defer:function(a){setTimeout(a,0)},debounce:function(a,b,c){var d,e;return function(){var f,g,h=this,i=arguments;return f=function(){d=null,c||(e=a.apply(h,i))},g=c&&!d,clearTimeout(d),d=setTimeout(f,b),g&&(e=a.apply(h,i)),e}},throttle:function(a,b){var c,d,e,f,g,h;return g=0,h=function(){g=new Date,e=null,f=a.apply(c,d)},function(){var i=new Date,j=b-(i-g);return c=this,d=arguments,0>=j?(clearTimeout(e),e=null,g=i,f=a.apply(c,d)):e||(e=setTimeout(h,j)),f}},stringify:function(a){return b.isString(a)?a:JSON.stringify(a)},noop:function(){}}}(),c="0.11.1",d=function(){"use strict";function a(a){return a=b.toStr(a),a?a.split(/\s+/):[]}function c(a){return a=b.toStr(a),a?a.split(/\W+/):[]}function d(a){return function(c){return c=b.isArray(c)?c:[].slice.call(arguments,0),function(d){var e=[];return b.each(c,function(c){e=e.concat(a(b.toStr(d[c])))}),e}}}return{nonword:c,whitespace:a,obj:{nonword:d(c),whitespace:d(a)}}}(),e=function(){"use strict";function c(c){this.maxSize=b.isNumber(c)?c:100,this.reset(),this.maxSize<=0&&(this.set=this.get=a.noop)}function d(){this.head=this.tail=null}function e(a,b){this.key=a,this.val=b,this.prev=this.next=null}return b.mixin(c.prototype,{set:function(a,b){var c,d=this.list.tail;this.size>=this.maxSize&&(this.list.remove(d),delete this.hash[d.key],this.size--),(c=this.hash[a])?(c.val=b,this.list.moveToFront(c)):(c=new e(a,b),this.list.add(c),this.hash[a]=c,this.size++)},get:function(a){var b=this.hash[a];return b?(this.list.moveToFront(b),b.val):void 0},reset:function(){this.size=0,this.hash={},this.list=new d}}),b.mixin(d.prototype,{add:function(a){this.head&&(a.next=this.head,this.head.prev=a),this.head=a,this.tail=this.tail||a},remove:function(a){a.prev?a.prev.next=a.next:this.head=a.next,a.next?a.next.prev=a.prev:this.tail=a.prev},moveToFront:function(a){this.remove(a),this.add(a)}}),c}(),f=function(){"use strict";function c(a,c){this.prefix=["__",a,"__"].join(""),this.ttlKey="__ttl__",this.keyMatcher=new RegExp("^"+b.escapeRegExChars(this.prefix)),this.ls=c||h,!this.ls&&this._noop()}function d(){return(new Date).getTime()}function e(a){return JSON.stringify(b.isUndefined(a)?null:a)}function f(b){return a.parseJSON(b)}function g(a){var b,c,d=[],e=h.length;for(b=0;e>b;b++)(c=h.key(b)).match(a)&&d.push(c.replace(a,""));return d}var h;try{h=window.localStorage,h.setItem("~~~","!"),h.removeItem("~~~")}catch(i){h=null}return b.mixin(c.prototype,{_prefix:function(a){return this.prefix+a},_ttlKey:function(a){return this._prefix(a)+this.ttlKey},_noop:function(){this.get=this.set=this.remove=this.clear=this.isExpired=b.noop},_safeSet:function(a,b){try{this.ls.setItem(a,b)}catch(c){"QuotaExceededError"===c.name&&(this.clear(),this._noop())}},get:function(a){return this.isExpired(a)&&this.remove(a),f(this.ls.getItem(this._prefix(a)))},set:function(a,c,f){return b.isNumber(f)?this._safeSet(this._ttlKey(a),e(d()+f)):this.ls.removeItem(this._ttlKey(a)),this._safeSet(this._prefix(a),e(c))},remove:function(a){return this.ls.removeItem(this._ttlKey(a)),this.ls.removeItem(this._prefix(a)),this},clear:function(){var a,b=g(this.keyMatcher);for(a=b.length;a--;)this.remove(b[a]);return this},isExpired:function(a){var c=f(this.ls.getItem(this._ttlKey(a)));return b.isNumber(c)&&d()>c?!0:!1}}),c}(),g=function(){"use strict";function c(a){a=a||{},this.cancelled=!1,this.lastReq=null,this._send=a.transport,this._get=a.limiter?a.limiter(this._get):this._get,this._cache=a.cache===!1?new e(0):h}var d=0,f={},g=6,h=new e(10);return c.setMaxPendingRequests=function(a){g=a},c.resetCache=function(){h.reset()},b.mixin(c.prototype,{_fingerprint:function(b){return b=b||{},b.url+b.type+a.param(b.data||{})},_get:function(a,b){function c(a){b(null,a),k._cache.set(i,a)}function e(){b(!0)}function h(){d--,delete f[i],k.onDeckRequestArgs&&(k._get.apply(k,k.onDeckRequestArgs),k.onDeckRequestArgs=null)}var i,j,k=this;i=this._fingerprint(a),this.cancelled||i!==this.lastReq||((j=f[i])?j.done(c).fail(e):g>d?(d++,f[i]=this._send(a).done(c).fail(e).always(h)):this.onDeckRequestArgs=[].slice.call(arguments,0))},get:function(c,d){var e,f;d=d||a.noop,c=b.isString(c)?{url:c}:c||{},f=this._fingerprint(c),this.cancelled=!1,this.lastReq=f,(e=this._cache.get(f))?d(null,e):this._get(c,d)},cancel:function(){this.cancelled=!0}}),c}(),h=window.SearchIndex=function(){"use strict";function c(c){c=c||{},c.datumTokenizer&&c.queryTokenizer||a.error("datumTokenizer and queryTokenizer are both required"),this.identify=c.identify||b.stringify,this.datumTokenizer=c.datumTokenizer,this.queryTokenizer=c.queryTokenizer,this.reset()}function d(a){return a=b.filter(a,function(a){return!!a}),a=b.map(a,function(a){return a.toLowerCase()})}function e(){var a={};return a[i]=[],a[h]={},a}function f(a){for(var b={},c=[],d=0,e=a.length;e>d;d++)b[a[d]]||(b[a[d]]=!0,c.push(a[d]));return c}function g(a,b){var c=0,d=0,e=[];a=a.sort(),b=b.sort();for(var f=a.length,g=b.length;f>c&&g>d;)a[c]b[d]?d++:(e.push(a[c]),c++,d++);return e}var h="c",i="i";return b.mixin(c.prototype,{bootstrap:function(a){this.datums=a.datums,this.trie=a.trie},add:function(a){var c=this;a=b.isArray(a)?a:[a],b.each(a,function(a){var f,g;c.datums[f=c.identify(a)]=a,g=d(c.datumTokenizer(a)),b.each(g,function(a){var b,d,g;for(b=c.trie,d=a.split("");g=d.shift();)b=b[h][g]||(b[h][g]=e()),b[i].push(f)})})},get:function(a){var c=this;return b.map(a,function(a){return c.datums[a]})},search:function(a){var c,e,j=this;return c=d(this.queryTokenizer(a)),b.each(c,function(a){var b,c,d,f;if(e&&0===e.length)return!1;for(b=j.trie,c=a.split("");b&&(d=c.shift());)b=b[h][d];return b&&0===c.length?(f=b[i].slice(0),void(e=e?g(e,f):f)):(e=[],!1)}),e?b.map(f(e),function(a){return j.datums[a]}):[]},all:function(){var a=[];for(var b in this.datums)a.push(this.datums[b]);return a},reset:function(){this.datums={},this.trie=e()},serialize:function(){return{datums:this.datums,trie:this.trie}}}),c}(),i=function(){"use strict";function a(a){this.url=a.url,this.ttl=a.ttl,this.cache=a.cache,this.prepare=a.prepare,this.transform=a.transform,this.transport=a.transport,this.thumbprint=a.thumbprint,this.storage=new f(a.cacheKey)}var c;return c={data:"data",protocol:"protocol",thumbprint:"thumbprint"},b.mixin(a.prototype,{_settings:function(){return{url:this.url,type:"GET",dataType:"json"}},store:function(a){this.cache&&(this.storage.set(c.data,a,this.ttl),this.storage.set(c.protocol,location.protocol,this.ttl),this.storage.set(c.thumbprint,this.thumbprint,this.ttl))},fromCache:function(){var a,b={};return this.cache?(b.data=this.storage.get(c.data),b.protocol=this.storage.get(c.protocol),b.thumbprint=this.storage.get(c.thumbprint),a=b.thumbprint!==this.thumbprint||b.protocol!==location.protocol,b.data&&!a?b.data:null):null},fromNetwork:function(a){function b(){a(!0)}function c(b){a(null,e.transform(b))}var d,e=this;a&&(d=this.prepare(this._settings()),this.transport(d).fail(b).done(c))},clear:function(){return this.storage.clear(),this}}),a}(),j=function(){"use strict";function a(a){this.url=a.url,this.prepare=a.prepare,this.transform=a.transform,this.transport=new g({cache:a.cache,limiter:a.limiter,transport:a.transport})}return b.mixin(a.prototype,{_settings:function(){return{url:this.url,type:"GET",dataType:"json"}},get:function(a,b){function c(a,c){b(a?[]:e.transform(c))}var d,e=this;if(b)return a=a||"",d=this.prepare(a,this._settings()),this.transport.get(d,c)},cancelLastRequest:function(){this.transport.cancel()}}),a}(),k=function(){"use strict";function d(d){var e;return d?(e={url:null,ttl:864e5,cache:!0,cacheKey:null,thumbprint:"",prepare:b.identity,transform:b.identity,transport:null},d=b.isString(d)?{url:d}:d,d=b.mixin(e,d),!d.url&&a.error("prefetch requires url to be set"),d.transform=d.filter||d.transform,d.cacheKey=d.cacheKey||d.url,d.thumbprint=c+d.thumbprint,d.transport=d.transport?h(d.transport):a.ajax,d):null}function e(c){var d;if(c)return d={url:null,cache:!0,prepare:null,replace:null,wildcard:null,limiter:null,rateLimitBy:"debounce",rateLimitWait:300,transform:b.identity,transport:null},c=b.isString(c)?{url:c}:c,c=b.mixin(d,c),!c.url&&a.error("remote requires url to be set"),c.transform=c.filter||c.transform,c.prepare=f(c),c.limiter=g(c),c.transport=c.transport?h(c.transport):a.ajax,delete c.replace,delete c.wildcard,delete c.rateLimitBy,delete c.rateLimitWait,c}function f(a){function b(a,b){return b.url=f(b.url,a),b}function c(a,b){return b.url=b.url.replace(g,encodeURIComponent(a)),b}function d(a,b){return b}var e,f,g;return e=a.prepare,f=a.replace,g=a.wildcard,e?e:e=f?b:a.wildcard?c:d}function g(a){function c(a){return function(c){return b.debounce(c,a)}}function d(a){return function(c){return b.throttle(c,a)}}var e,f,g;return e=a.limiter,f=a.rateLimitBy,g=a.rateLimitWait,e||(e=/^throttle$/i.test(f)?d(g):c(g)),e}function h(c){return function(d){function e(a){b.defer(function(){g.resolve(a)})}function f(a){b.defer(function(){g.reject(a)})}var g=a.Deferred();return c(d,e,f),g}}return function(c){var f,g;return f={initialize:!0,identify:b.stringify,datumTokenizer:null,queryTokenizer:null,sufficient:5,sorter:null,local:[],prefetch:null,remote:null},c=b.mixin(f,c||{}),!c.datumTokenizer&&a.error("datumTokenizer is required"),!c.queryTokenizer&&a.error("queryTokenizer is required"),g=c.sorter,c.sorter=g?function(a){return a.sort(g)}:b.identity,c.local=b.isFunction(c.local)?c.local():c.local,c.prefetch=d(c.prefetch),c.remote=e(c.remote),c}}(),l=function(){"use strict";function c(a){a=k(a),this.sorter=a.sorter,this.identify=a.identify,this.sufficient=a.sufficient,this.local=a.local,this.remote=a.remote?new j(a.remote):null,this.prefetch=a.prefetch?new i(a.prefetch):null,this.index=new h({identify:this.identify,datumTokenizer:a.datumTokenizer,queryTokenizer:a.queryTokenizer}),a.initialize!==!1&&this.initialize()}var e;return e=window&&window.Bloodhound,c.noConflict=function(){return window&&(window.Bloodhound=e),c},c.tokenizers=d,b.mixin(c.prototype,{__ttAdapter:function(){function a(a,b,d){return c.search(a,b,d)}function b(a,b){return c.search(a,b)}var c=this;return this.remote?a:b},_loadPrefetch:function(){function b(a,b){return a?c.reject():(e.add(b),e.prefetch.store(e.index.serialize()),void c.resolve())}var c,d,e=this;return c=a.Deferred(),this.prefetch?(d=this.prefetch.fromCache())?(this.index.bootstrap(d),c.resolve()):this.prefetch.fromNetwork(b):c.resolve(),c.promise()},_initialize:function(){function a(){b.add(b.local)}var b=this;return this.clear(),(this.initPromise=this._loadPrefetch()).done(a),this.initPromise},initialize:function(a){return!this.initPromise||a?this._initialize():this.initPromise},add:function(a){return this.index.add(a),this},get:function(a){return a=b.isArray(a)?a:[].slice.call(arguments),this.index.get(a)},search:function(a,c,d){function e(a){var c=[];b.each(a,function(a){!b.some(f,function(b){return g.identify(a)===g.identify(b)})&&c.push(a)}),d&&d(c)}var f,g=this;return f=this.sorter(this.index.search(a)),c(this.remote?f.slice():f),this.remote&&f.length=j?(clearTimeout(e),e=null,g=i,f=a.apply(c,d)):e||(e=setTimeout(h,j)),f}},stringify:function(a){return b.isString(a)?a:JSON.stringify(a)},noop:function(){}}}(),c=function(){"use strict";function a(a){var g,h;return h=b.mixin({},f,a),g={css:e(),classes:h,html:c(h),selectors:d(h)},{css:g.css,html:g.html,classes:g.classes,selectors:g.selectors,mixin:function(a){b.mixin(a,g)}}}function c(a){return{wrapper:'',menu:'
'}}function d(a){var c={};return b.each(a,function(a,b){c[b]="."+a}),c}function e(){var a={wrapper:{position:"relative",display:"inline-block"},hint:{position:"absolute",top:"0",left:"0",borderColor:"transparent",boxShadow:"none",opacity:"1"},input:{position:"relative",verticalAlign:"top",backgroundColor:"transparent"},inputWithNoHint:{position:"relative",verticalAlign:"top"},menu:{position:"absolute",top:"100%",left:"0",zIndex:"100",display:"none"},ltr:{left:"0",right:"auto"},rtl:{left:"auto",right:" 0"}};return b.isMsie()&&b.mixin(a.input,{backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"}),a}var f={wrapper:"twitter-typeahead",input:"tt-input",hint:"tt-hint",menu:"tt-menu",dataset:"tt-dataset",suggestion:"tt-suggestion",selectable:"tt-selectable",empty:"tt-empty",open:"tt-open",cursor:"tt-cursor",highlight:"tt-highlight"};return a}(),d=function(){"use strict";function c(b){b&&b.el||a.error("EventBus initialized without el"),this.$el=a(b.el)}var d,e;return d="typeahead:",e={render:"rendered",cursorchange:"cursorchanged",select:"selected",autocomplete:"autocompleted"},b.mixin(c.prototype,{_trigger:function(b,c){var e;return e=a.Event(d+b),(c=c||[]).unshift(e),this.$el.trigger.apply(this.$el,c),e},before:function(a){var b,c;return b=[].slice.call(arguments,1),c=this._trigger("before"+a,b),c.isDefaultPrevented()},trigger:function(a){var b;this._trigger(a,[].slice.call(arguments,1)),(b=e[a])&&this._trigger(b,[].slice.call(arguments,1))}}),c}(),e=function(){"use strict";function a(a,b,c,d){var e;if(!c)return this;for(b=b.split(i),c=d?h(c,d):c,this._callbacks=this._callbacks||{};e=b.shift();)this._callbacks[e]=this._callbacks[e]||{sync:[],async:[]},this._callbacks[e][a].push(c);return this}function b(b,c,d){return a.call(this,"async",b,c,d)}function c(b,c,d){return a.call(this,"sync",b,c,d)}function d(a){var b;if(!this._callbacks)return this;for(a=a.split(i);b=a.shift();)delete this._callbacks[b];return this}function e(a){var b,c,d,e,g;if(!this._callbacks)return this;for(a=a.split(i),d=[].slice.call(arguments,1);(b=a.shift())&&(c=this._callbacks[b]);)e=f(c.sync,this,[b].concat(d)),g=f(c.async,this,[b].concat(d)),e()&&j(g);return this}function f(a,b,c){function d(){for(var d,e=0,f=a.length;!d&&f>e;e+=1)d=a[e].apply(b,c)===!1;return!d}return d}function g(){var a;return a=window.setImmediate?function(a){setImmediate(function(){a()})}:function(a){setTimeout(function(){a()},0)}}function h(a,b){return a.bind?a.bind(b):function(){a.apply(b,[].slice.call(arguments,0))}}var i=/\s+/,j=g();return{onSync:c,onAsync:b,off:d,trigger:e}}(),f=function(a){"use strict";function c(a,c,d){for(var e,f=[],g=0,h=a.length;h>g;g++)f.push(b.escapeRegExChars(a[g]));return e=d?"\\b("+f.join("|")+")\\b":"("+f.join("|")+")",c?new RegExp(e):new RegExp(e,"i")}var d={node:null,pattern:null,tagName:"strong",className:null,wordsOnly:!1,caseSensitive:!1};return function(e){function f(b){var c,d,f;return(c=h.exec(b.data))&&(f=a.createElement(e.tagName),e.className&&(f.className=e.className),d=b.splitText(c.index),d.splitText(c[0].length),f.appendChild(d.cloneNode(!0)),b.parentNode.replaceChild(f,d)),!!c}function g(a,b){for(var c,d=3,e=0;e