├── __init__.py ├── app ├── __init__.py ├── dictionary.toml.words ├── dictionary.mm.words ├── dictionary.hosts.words ├── dictionary.css.words ├── dictionary.md.words ├── dictionary.proto.words ├── dictionary.fidl.words ├── config.py ├── dictionary.contractions.words ├── dictionary.en-misc.words ├── dictionary.golang.words ├── dictionary.gn.words ├── dictionary.en-gb.words ├── formatter.py ├── dictionary.bash.words ├── dictionary.en-abbreviations.words ├── unit_test_line_buffer.py ├── unit_test_string.py ├── color.py ├── dictionary.html.words ├── render.py ├── dictionary.rs.words ├── unit_test_regex.py ├── unit_test_misspellings.py ├── profile.py ├── clipboard.py ├── unit_test_prefs.py ├── string.py ├── unit_test_execute_prompt.py ├── unit_test_startup.py ├── unit_test_prediction_window.py ├── vi_editor.py ├── dictionary.chromium.words ├── regex.py ├── unit_test_intention.py ├── buffer_file.py ├── dictionary.fuchsia.words ├── line_buffer.py ├── dictionary.acronyms.words ├── bookmark.py ├── help.py ├── unit_test_buffer_file.py ├── unit_test_undo_redo.py ├── sm_editor.py ├── debug_window.py ├── dictionary.py.words ├── background.py ├── buffer_manager.py ├── unit_test_text_buffer.py ├── unit_test_copy_paste.py └── dictionary.cpp.words ├── rust ├── .gitignore ├── rustfmt.toml ├── Cargo.toml ├── src │ ├── main.rs │ ├── buffer_manager.rs │ ├── prefs.rs │ └── ci_program.rs ├── readme.md └── Cargo.lock ├── third_party ├── __init__.py └── pyperclip │ ├── readme.md │ ├── exceptions.py │ ├── LICENSE.txt │ ├── __init__.py │ └── clipboards.py ├── sample ├── spelling_test ├── ._ A name with cr │ └── example ├── chromium │ └── spelling_test ├── badChars ├── binary_test_file ├── tabs ├── sample.rs ├── valid_unicode ├── sample.go ├── sample.js ├── sample.py ├── sample.h ├── sample.cc └── sample.html ├── .gitignore ├── _config.yml ├── AUTHORS ├── docs ├── style_guide.md └── keyBindings ├── tools ├── full_test ├── presub ├── rename_code.py └── checkSpelling.py ├── test_fake └── curses │ ├── __init__.py │ ├── ascii.py │ └── constants.py ├── __main__.py ├── design ├── glossary.md ├── save_logic.md └── find ├── CONTRIBUTING ├── setup.py ├── ci.py ├── help.md ├── install.sh └── unit_tests.py /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rust/.gitignore: -------------------------------------------------------------------------------- 1 | target/ -------------------------------------------------------------------------------- /third_party/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/dictionary.toml.words: -------------------------------------------------------------------------------- 1 | pistoncore 2 | glutin 3 | -------------------------------------------------------------------------------- /sample/spelling_test: -------------------------------------------------------------------------------- 1 | one 2 | fieldtrialtriggered 3 | -------------------------------------------------------------------------------- /sample/._ A name with cr /example: -------------------------------------------------------------------------------- 1 | File in a \r directory. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .coverage 2 | *.pyc 3 | *.pyo 4 | *~ 5 | \#* 6 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | show_downloads: true 2 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /rust/rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 80 2 | newline_style = "Unix" 3 | -------------------------------------------------------------------------------- /sample/chromium/spelling_test: -------------------------------------------------------------------------------- 1 | one 2 | fieldtrialtriggered 3 | -------------------------------------------------------------------------------- /sample/badChars: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/ci_edit/HEAD/sample/badChars -------------------------------------------------------------------------------- /sample/binary_test_file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/ci_edit/HEAD/sample/binary_test_file -------------------------------------------------------------------------------- /rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust" 3 | version = "0.1.0" 4 | authors = ["Dave Schuyler "] 5 | 6 | [dependencies] 7 | ncurses = "5.97.0" -------------------------------------------------------------------------------- /sample/tabs: -------------------------------------------------------------------------------- 1 | < 7 | <2tabs 8 | line with tabs 9 | ends with tab> 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /third_party/pyperclip/readme.md: -------------------------------------------------------------------------------- 1 | ### Partial library 2 | 3 | This is not a full version of pyperclip. This version is included in ci_edit and 4 | contains the bits needed for that application. To get the full pyperclip library 5 | please visit: https://github.com/asweigart/pyperclip -------------------------------------------------------------------------------- /sample/sample.rs: -------------------------------------------------------------------------------- 1 | 2 | fn main { 3 | let stuff = b'H'; // Binary character. 4 | let stuff = b"Hello,"; // Binary string. 5 | let stuff = br###"Hello, a double quote (") is in this string."###; 6 | let stuff = r###"Hello, a dzouble quote (") is in this string."###; 7 | } -------------------------------------------------------------------------------- /sample/valid_unicode: -------------------------------------------------------------------------------- 1 | According to (Google translate, these all mean)xx "hello": 2 | Chào bạn 3 | Здравствуйте 4 | こんにちはtranslate 5 | こんにちはtranslate123 if (1) { print "hello" } 6 | 7 | こ 8 | 9 | aこbcこdeこ 10 | 11 | こんにちは 12 | 1234567890 13 | 14 | 15 | one two 16 | こんにちは 17 | 18 | a😀😀four 19 | 20 | a😀four 21 | -------------------------------------------------------------------------------- /third_party/pyperclip/exceptions.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | 3 | 4 | class PyperclipException(RuntimeError): 5 | pass 6 | 7 | 8 | class PyperclipWindowsException(PyperclipException): 9 | def __init__(self, message): 10 | message += " (%s)" % ctypes.WinError() 11 | super(PyperclipWindowsException, self).__init__(message) 12 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the list of ci_edit authors for copyright purposes. 2 | # 3 | # This does not necessarily list everyone who has contributed code, since in 4 | # some cases, their employer may be the copyright holder. To see the full list 5 | # of contributors, see the revision history in source control. 6 | Google Inc. 7 | David Schuyler 8 | and other contributors 9 | -------------------------------------------------------------------------------- /docs/style_guide.md: -------------------------------------------------------------------------------- 1 | # Coding Style Guides for ci_edit 2 | 3 | ## Python Style Guide 4 | 5 | The initial ci_edit code followed a style similar to the Chromium Python style 6 | guide. Over time, the ci_edit style will migrate towards the Google Python style 7 | guide which is much closer to PEP-8. Some of that style can be attained with 8 | yapf. E.g. 9 | 10 | $ yapf -i --style google ci.py 11 | 12 | ## Rust Style Guide 13 | 14 | Use rustfmt, e.g. 15 | 16 | $ cargo fmt 17 | -------------------------------------------------------------------------------- /tools/full_test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | unit_tests="$(dirname "$0")/../unit_tests.py" 4 | 5 | echo -e "\n\nPython with threads" && \ 6 | python --version && \ 7 | python "$unit_tests" $* && \ 8 | echo -e "\n\nPython3 with threads\n $(python3 --version)" && \ 9 | python3 "$unit_tests" $* && \ 10 | echo -e "\n\nPython single thread\n $(python --version)" && \ 11 | CI_EDIT_SINGLE_THREAD="1" python "$unit_tests" $* && \ 12 | echo -e "\n\nPython3 single thread\n $(python3 --version)" && \ 13 | CI_EDIT_SINGLE_THREAD="1" python3 "$unit_tests" $* -------------------------------------------------------------------------------- /tools/presub: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | process() { 4 | echo "Processing $1" 5 | # Use `black` instead of `yapf` 6 | # yapf -i --style google "$1" 7 | black --exclude sample . 8 | #docformatter -i --wrap-summaries 80 --wrap-descriptions 80 "$1" 9 | pylint -d unused-argument -d attribute-defined-outside-init \ 10 | -d undefined-variable -d wildcard-import -d redefined-builtin "$1" 11 | } 12 | 13 | if [ "$1" != "" ]; then 14 | fileList=$* 15 | else 16 | fileList=`git diff master --name-only` 17 | fi 18 | 19 | for i in $fileList; do 20 | if [ "${i: -3}" == ".py" ]; then 21 | process "$i" 22 | fi 23 | done 24 | -------------------------------------------------------------------------------- /app/dictionary.mm.words: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | nsobject -------------------------------------------------------------------------------- /app/dictionary.hosts.words: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | allnodes 16 | allhosts 17 | allrouters 18 | -------------------------------------------------------------------------------- /app/dictionary.css.words: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | dp 16 | lightblue 17 | lightgray 18 | lightgrey 19 | px 20 | woff 21 | -------------------------------------------------------------------------------- /app/dictionary.md.words: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Non-words that legitimately appear in .md (markdown) files. 16 | mdash 17 | -------------------------------------------------------------------------------- /app/dictionary.proto.words: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # This is a list of non-English words that are in proto buffer scripts. 16 | bytestream 17 | protos -------------------------------------------------------------------------------- /test_fake/curses/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from .constants import * 16 | from .curses import * 17 | 18 | # __all__ = ["ascii", "contants", "curses"] 19 | -------------------------------------------------------------------------------- /app/dictionary.fidl.words: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # This is a list of non-English words that are commonly found in fidl source 16 | # code files. 17 | 18 | channelcontrol -------------------------------------------------------------------------------- /__main__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import app.ci_program 16 | 17 | # This command will run if the module is executed as "python ci_edit". 18 | app.ci_program.run_ci() 19 | -------------------------------------------------------------------------------- /app/config.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | strict_debug = False 20 | -------------------------------------------------------------------------------- /rust/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | mod buffer_manager; 16 | mod ci_program; 17 | mod color; 18 | mod prefs; 19 | mod text_buffer; 20 | 21 | fn main() { 22 | ci_program::run_ci(); 23 | } 24 | -------------------------------------------------------------------------------- /test_fake/curses/ascii.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | ESC = 27 20 | BS = 2 21 | DEL = 3 22 | 23 | 24 | def isprint(*args): 25 | return 31 < args[0] <= 127 26 | -------------------------------------------------------------------------------- /app/dictionary.contractions.words: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # This is a list of English word contractions. 16 | aren't 17 | couldn't 18 | didn't 19 | doesn't 20 | don't 21 | hasn't 22 | i'll 23 | isn't 24 | shouldn't 25 | wasn't 26 | we'll 27 | we're 28 | we've 29 | weren't 30 | won't 31 | wouldn't 32 | -------------------------------------------------------------------------------- /app/dictionary.en-misc.words: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | # Lorem ipsum 17 | adipiscing 18 | amet 19 | consectetur 20 | elit 21 | 22 | 23 | # Slang 24 | doxing 25 | 26 | 27 | # Unfiled (todo) 28 | crx 29 | embedder 30 | foobarbaz 31 | teardown 32 | typedeffed 33 | webcal 34 | webprefs 35 | xkb 36 | -------------------------------------------------------------------------------- /app/dictionary.golang.words: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # This is a list of non-English words that are in the Go programming language 16 | # libraries. 17 | bufio 18 | cond 19 | fatalf 20 | filepath 21 | fmt 22 | fprintln 23 | getenv 24 | ioutil 25 | mkdir 26 | println 27 | rdwr 28 | readdirnames 29 | sprintf 30 | strconv 31 | tabwriter 32 | -------------------------------------------------------------------------------- /app/dictionary.gn.words: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # This is a list of non-English words that are in gn scripts. 16 | argh 17 | browsertests 18 | buildargs 19 | cflags 20 | depfile 21 | envs 22 | gn 23 | gni 24 | javagen 25 | ldflags 26 | mockall 27 | objcc 28 | plist 29 | pytype 30 | serde 31 | tempfile 32 | termion 33 | testonly 34 | thiserror 35 | toplevel 36 | valico 37 | -------------------------------------------------------------------------------- /rust/readme.md: -------------------------------------------------------------------------------- 1 | # The ci_edit/rust directory 2 | 3 | This directory is the start of a Rust version of ci_edit. The initial prototype 4 | was done in Python, which has performed surprisingly well. 5 | 6 | While this version of ci_edit is in development it can be ignored by most users. 7 | There's no need to compile or install this version. 8 | 9 | 10 | ## Note 11 | 12 | This is not an official Google product. 13 | 14 | 15 | 16 | Copyright 2018 Google Inc. 17 | 18 | Licensed under the Apache License, Version 2.0 (the "License"); 19 | you may not use this file except in compliance with the License. 20 | You may obtain a copy of the License at 21 | 22 | http://www.apache.org/licenses/LICENSE-2.0 23 | 24 | Unless required by applicable law or agreed to in writing, software 25 | distributed under the License is distributed on an "AS IS" BASIS, 26 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 27 | See the License for the specific language governing permissions and 28 | limitations under the License. 29 | 30 | -------------------------------------------------------------------------------- /app/dictionary.en-gb.words: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | behaviour 16 | cancelled 17 | characterise 18 | colour 19 | coloured 20 | colouring 21 | colours 22 | copiable 23 | copyable 24 | favour 25 | favourable 26 | favourite 27 | flavour 28 | flavoured 29 | flavours 30 | grey 31 | honour 32 | honours 33 | humour 34 | humoured 35 | labelling 36 | localiser 37 | modularization 38 | neighbour 39 | neighbourhood 40 | offence 41 | offences 42 | travelled 43 | -------------------------------------------------------------------------------- /app/formatter.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """Formatters.""" 15 | 16 | from __future__ import absolute_import 17 | from __future__ import division 18 | from __future__ import print_function 19 | 20 | 21 | def format_python(text): 22 | try: 23 | import black 24 | except ImportError: 25 | raise RuntimeError(u"install black formatter to format: pip install black") 26 | 27 | return black.format_str(text, mode=black.FileMode()) 28 | -------------------------------------------------------------------------------- /app/dictionary.bash.words: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # This is a list of non-English words that are in Bash/shell scripts. 16 | autoconf 17 | awk 18 | cd 19 | chmod 20 | chown 21 | cp 22 | dlog 23 | env 24 | grep 25 | ln 26 | ls 27 | mkdir 28 | mktemp 29 | rf 30 | rm 31 | rmdir 32 | rsync 33 | sbin 34 | sed 35 | shellcheck 36 | strace 37 | symlink 38 | udev 39 | udevadm 40 | ulimit 41 | uname 42 | usr 43 | vcs 44 | vlog 45 | wc 46 | xargs 47 | xattr 48 | xserver 49 | -------------------------------------------------------------------------------- /app/dictionary.en-abbreviations.words: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Abbreviations 16 | apr 17 | aug 18 | bidi 19 | blvd 20 | concat 21 | config 22 | crypto 23 | dbg 24 | dec 25 | dev 26 | expr 27 | feb 28 | fri 29 | fs 30 | idl 31 | ipc 32 | isp 33 | iter 34 | jan 35 | jr 36 | jul 37 | lang 38 | mem 39 | mon 40 | mrs 41 | mut 42 | nd 43 | nov 44 | oct 45 | ok 46 | perf 47 | rd 48 | rfc 49 | sep 50 | sept 51 | st 52 | thu 53 | topo 54 | tos 55 | tue 56 | tv 57 | ux 58 | ver 59 | vm 60 | yaml 61 | -------------------------------------------------------------------------------- /docs/keyBindings: -------------------------------------------------------------------------------- 1 | 2 | Common keyboard shortcuts: 3 | 4 | Text commands (such as cut and paste) 5 | operate on the text where the cursor is 6 | located text rather than the main window. 7 | 8 | ctrl+a Select all 9 | ctrl+c Copy 10 | ctrl+l Select current line (subsequent select next line) 11 | ctrl+q Quit (exit editor) 12 | crtl+w Close buffer 13 | ctrl+s Save file 14 | ctrl+v Paste 15 | ctrl+x Cut 16 | ctrl+y Redo 17 | ctrl+z Undo 18 | esc Return to the main window 19 | 20 | 21 | Within the main text window: 22 | 23 | ctrl+f Find 24 | ctrl+g Go to line 25 | ctrl+r Reverse find 26 | 27 | 28 | Within Find: 29 | 30 | return Return to main window 31 | esc Return to main window 32 | ctrl+f Find next 33 | ctrl+g Find next 34 | ctrl+r Reverse find 35 | 36 | 37 | Within Goto: 38 | 39 | return Go to the line, column specified 40 | esc Return to main window 41 | t Jump to top of buffer 42 | h Jump to halfway point of buffer 43 | b Jump to bottom of buffer 44 | -------------------------------------------------------------------------------- /sample/sample.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // This is a Go language sample file. It's not real code, it's used for parsing 16 | // and highlighting tests. 17 | 18 | package main 19 | 20 | import ( 21 | "flag" 22 | "fmt" 23 | "log" 24 | "os" 25 | "path/filepath" 26 | "runtime/trace" 27 | ) 28 | 29 | const usage = `Usage: %s 30 | blah blah 31 | another line. 32 | ` 33 | 34 | func doMain() int { 35 | fmt.Fprintf(os.Stderr, usage, filepath.Base(os.Args[0])) 36 | fmt.Fprintln(os.Stderr) 37 | return 0 38 | } 39 | 40 | func main() { 41 | os.Exit(doMain()) 42 | } 43 | -------------------------------------------------------------------------------- /sample/sample.js: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /* normal comment @param */ 16 | # not a comment 17 | 18 | /** doc comment 19 | * @param 20 | * @return {boolean} 21 | */ 22 | namespace is not a keyword 23 | // line comment @param 24 | 25 | if while for 26 | a = b/c; 27 | a = b / c; 28 | 29 | a = `one \${o} two ${three} fo\nu\`r`; 30 | 31 | a = /.*/; 32 | /as/ 33 | 34 | function foo() { 35 | if or while or switch 36 | bar(/\r\ne\/gex"/, 'thing') 37 | } 38 | 39 | /sdfsdf/: /fefe/; 40 | 41 | a = /sdfdf/; 42 | foo(/eeef.*/, 4, /sdf/); 43 | 44 | // (?!(?<=[\w/*\s]))\s*/(?![/*]) 45 | 'sadfsds\nsadf' // 46 | "wfefw\\ \" safsf" // -------------------------------------------------------------------------------- /rust/src/buffer_manager.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use super::ci_program::CiProgram; 16 | use super::prefs::Prefs; 17 | use super::text_buffer::TextBuffer; 18 | use std::sync::Arc; 19 | 20 | pub struct BufferManager { 21 | pub program: Option>, 22 | buffers: Vec, 23 | } 24 | 25 | impl BufferManager { 26 | //pub fn new(program: RefCell>) -> BufferManager { 27 | pub fn new() -> BufferManager { 28 | BufferManager { 29 | program: None, 30 | //prefs: prefs::Prefs::new(), 31 | buffers: vec![], 32 | } 33 | } 34 | 35 | pub fn init(&mut self) {} 36 | 37 | pub fn set_up_palette(&mut self) {} 38 | } 39 | -------------------------------------------------------------------------------- /app/unit_test_line_buffer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | import unittest 20 | 21 | import app.log 22 | import app.ci_program 23 | import app.line_buffer 24 | 25 | 26 | class LineBufferTestCases(unittest.TestCase): 27 | def setUp(self): 28 | self.line_buffer = app.line_buffer.LineBuffer(app.ci_program.CiProgram()) 29 | app.log.shouldWritePrintLog = True 30 | 31 | def tearDown(self): 32 | self.line_buffer = None 33 | 34 | def test_create(self): 35 | self.assertTrue(self.line_buffer is not None) 36 | 37 | 38 | if __name__ == "__main__": 39 | unittest.main() 40 | -------------------------------------------------------------------------------- /design/glossary.md: -------------------------------------------------------------------------------- 1 | 2 | # Glossary of terms used in the program source. 3 | 4 | Note: this information is not useful for *using* the editor. It's intended for 5 | those working on (programming) the editor itself. 6 | 7 | child 8 | - a window 9 | - reference to a window contained by this window 10 | - a parent may have 0..* children 11 | - property of parent 12 | 13 | contractor (? I'm still considering this term) 14 | - a window 15 | - doing work on or for a host 16 | - a host will have 0..1 contractor 17 | - property of host 18 | 19 | controller 20 | - a controller 21 | - keybindings 22 | - a controller will have 1..1 view 23 | - property of view 24 | 25 | host 26 | - a window 27 | - the view requesting work 28 | - likely the parent, but not necessarily the parent 29 | - a contractor will have 0..1 host 30 | - property of contractor 31 | 32 | parent 33 | - a window 34 | - The window holding this window 35 | - The given window is a child of the parent 36 | - a child will have 1..1 parent (the top parent is the program instance) 37 | - property of child 38 | 39 | view 40 | - a window 41 | - the window for a given controller 42 | - controller and view are 1:1 43 | - a view will have 1..1 model (an empty model will be created for the view if 44 | necessary) 45 | - property of a controller 46 | - property of a model 47 | 48 | model 49 | - a text buffer 50 | - a mutator 51 | - a model will have 0..* views 52 | -------------------------------------------------------------------------------- /app/unit_test_string.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | import curses 20 | import unittest 21 | 22 | import app.string 23 | 24 | 25 | class StringTestCases(unittest.TestCase): 26 | def test_path_encode(self): 27 | tests = [ 28 | (u"abcd", u"abcd"), 29 | (u"\rabcd", u"\\rabcd"), 30 | (u"ab\rcd", u"ab\\rcd"), 31 | (u"abcd\r", u"abcd\\r"), 32 | (u"\aab\tcd\r", u"\\aab\\tcd\\r"), 33 | (u"abcd\\", u"abcd\\\\"), 34 | (u"\\", u"\\\\"), 35 | ] 36 | for test in tests: 37 | self.assertEqual(app.string.path_encode(test[0]), test[1]) 38 | self.assertEqual(app.string.path_decode(test[1]), test[0]) 39 | -------------------------------------------------------------------------------- /app/color.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | import curses 20 | 21 | 22 | class Colors: 23 | def __init__(self, colorPrefs): 24 | self.__colorPrefs = colorPrefs 25 | self.colors = 256 26 | self.__cache = {} 27 | 28 | def get(self, colorType, delta=0): 29 | if type(colorType) == type(0): 30 | colorIndex = colorType 31 | else: 32 | colorIndex = self.__colorPrefs[colorType] 33 | colorIndex = min(self.colors - 1, colorIndex + delta) 34 | color = self.__cache.get(colorIndex) or curses.color_pair(colorIndex) 35 | self.__cache[colorIndex] = color 36 | if colorType in ("error", "misspelling"): 37 | color |= curses.A_BOLD | curses.A_REVERSE 38 | return color 39 | -------------------------------------------------------------------------------- /sample/sample.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Python comment 16 | /* Not a comment */ 17 | /** Not a comment */ 18 | 19 | // Not a comment 20 | 21 | 22 | # TODO(dschuyler): A test comment. 23 | 24 | 'a\\' # double escape 25 | 'a\\\\' # quadruple escape 26 | 'a\02112s\0a\01b\012cfd23323sa' # numbers 27 | '\nfiller\w\\aaa\adf\bfsdf\'d\\\'sdff' # special values 28 | 29 | "a\\" # double escape 30 | "a\\\\" # quadruple escape 31 | "filler\nsfas\w\\aaa\adf\bfsdf\"d\\\"sadff" # special values 32 | 33 | '''asd\nsad'a"fsadf''' # triple single quotes 34 | r'''asd\nsad'a"fsadf''' # triple single quotes 35 | 36 | """asd\nsad'a"fsadf""" # triple double quotes 37 | r"""asd\nsad'a"fsadf""" # triple double quotes 38 | 39 | class Foo: 40 | def __init__(self, data): 41 | print data 42 | 43 | def blah(self): 44 | pass 45 | 46 | -------------------------------------------------------------------------------- /app/dictionary.html.words: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # HTML/JS 16 | animationend 17 | apn 18 | autocapitalize 19 | autocomplete 20 | autocorrect 21 | autofocus 22 | autosave 23 | br 24 | cellpadding 25 | cellspacing 26 | charset 27 | dataset 28 | defs 29 | describedat 30 | describedby 31 | doctype 32 | dragstart 33 | el 34 | enctype 35 | evenodd 36 | falsy 37 | fieldset 38 | flexbox 39 | hd 40 | href 41 | iconset 42 | iframe 43 | inputmode 44 | isdir 45 | keydown 46 | keypress 47 | keypresses 48 | labelledby 49 | li 50 | lt 51 | mailto 52 | maxlength 53 | minlength 54 | moz 55 | nameserver 56 | nameservers 57 | nbsp 58 | noink 59 | notranslate 60 | nowrap 61 | onclick 62 | onload 63 | pathname 64 | ph 65 | pollyfill 66 | popstate 67 | puk 68 | readonly 69 | roboto 70 | siminfo 71 | stringify 72 | substr 73 | tabindex 74 | tbody 75 | td 76 | textdirection 77 | th 78 | thead 79 | theader 80 | transitionend 81 | truthy 82 | tspan 83 | typeof 84 | ul 85 | -------------------------------------------------------------------------------- /app/render.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | 20 | class Frame: 21 | def __init__(self): 22 | # Track the total number of commands processed to create this frame. 23 | # This is used to match a point in the command stream to a frame. 24 | self.cmdCount = None 25 | self.cursor = None 26 | self.drawList = [] 27 | 28 | def add_str(self, row, col, text, style): 29 | self.drawList.append((row, col, text, style)) 30 | 31 | def set_cmd_count(self, count): 32 | self.cmdCount = count 33 | 34 | def set_cursor(self, cursor): 35 | self.cursor = cursor 36 | 37 | def grab_frame(self): 38 | r = self.drawList, self.cursor, self.cmdCount 39 | self.drawList = [] 40 | self.cursor = None 41 | self.cmdCount = None 42 | return r 43 | -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | Want to contribute? Great! First, read this page (including the small print at 2 | the end). 3 | 4 | ### Before you contribute 5 | Before we can use your code, you must sign the 6 | [Google Individual Contributor License Agreement] 7 | (https://cla.developers.google.com/about/google-individual) 8 | (CLA), which you can do online. The CLA is necessary mainly because you own the 9 | copyright to your changes, even after your contribution becomes part of our 10 | codebase, so we need your permission to use and distribute your code. We also 11 | need to be sure of various other things—for instance that you'll tell us if you 12 | know that your code infringes on other people's patents. You don't have to sign 13 | the CLA until after you've submitted your code for review and a member has 14 | approved it, but you must do it before we can put your code into our codebase. 15 | Before you start working on a larger contribution, you should get in touch with 16 | us first through the issue tracker with your idea so that we can help out and 17 | possibly guide you. Coordinating up front makes it much easier to avoid 18 | frustration later on. 19 | 20 | ### Code reviews 21 | All submissions, including submissions by project members, require review. We 22 | use Github pull requests for this purpose. 23 | 24 | ### The small print 25 | Contributions made by corporations are covered by a different agreement than 26 | the one above, the 27 | [Software Grant and Corporate Contributor License Agreement] 28 | (https://cla.developers.google.com/about/google-corporate). 29 | -------------------------------------------------------------------------------- /design/save_logic.md: -------------------------------------------------------------------------------- 1 | 2 | Note: these are outline notes I used to work through design issues. They 3 | probably don't make a lot of sense to another reader at the moment. My 4 | apologies. 5 | 6 | 7 | def is_safe_to_write 8 | t) write 9 | f) confirm_overwrite 10 | y) write 11 | n) switch_to_host 12 | 13 | ui_quit 14 | is_dirty 15 | t) message: this file is not saved, please save or close it. 16 | switch_to_host 17 | f) has_unsaved 18 | t) switch_to_unsaved, 19 | message: this file is not saved, please save or close it. 20 | switch_to_host 21 | f) quit_now 22 | 23 | too complicated: ui_quit 24 | is_dirty 25 | t) confirm_save 26 | y) is_safe_to_write 27 | t) write 28 | f) confirm_overwrite 29 | y) write, 30 | has_unsaved 31 | n) switch_to_host (cancel the quit) 32 | n) close_buffer_now, 33 | has_unsaved 34 | c) switch_to_host (cancel the quit) 35 | f) has_unsaved 36 | t) switch_to_unsaved, 37 | is_dirty 38 | f) quit_now 39 | f) confirm_overwrite 40 | y) write, 41 | has_unsaved 42 | n) switch_to_host (cancel the quit) 43 | 44 | ui_save 45 | is_dirty 46 | t) is_safe_to_write 47 | f) switch_to_host 48 | 49 | ui_save_as 50 | cr) is_safe_to_write 51 | esc) switch_to_host 52 | -------------------------------------------------------------------------------- /rust/Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "cc" 3 | version = "1.0.25" 4 | source = "registry+https://github.com/rust-lang/crates.io-index" 5 | 6 | [[package]] 7 | name = "libc" 8 | version = "0.2.44" 9 | source = "registry+https://github.com/rust-lang/crates.io-index" 10 | 11 | [[package]] 12 | name = "ncurses" 13 | version = "5.97.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | dependencies = [ 16 | "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", 17 | "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", 18 | "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", 19 | ] 20 | 21 | [[package]] 22 | name = "pkg-config" 23 | version = "0.3.14" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | 26 | [[package]] 27 | name = "rust" 28 | version = "0.1.0" 29 | dependencies = [ 30 | "ncurses 5.97.0 (registry+https://github.com/rust-lang/crates.io-index)", 31 | ] 32 | 33 | [metadata] 34 | "checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" 35 | "checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311" 36 | "checksum ncurses 5.97.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee821144e7fe6fd1d1c04b8001d92d783ae471a71d60ab506e6c608b83a85ae6" 37 | "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" 38 | -------------------------------------------------------------------------------- /third_party/pyperclip/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Al Sweigart 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the {organization} nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /app/dictionary.rs.words: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # This is a list of non-English words that are in Rust libraries (crates). 16 | argh 17 | atty 18 | automock 19 | bstate 20 | certifi 21 | chacha 22 | clippy 23 | consts 24 | crossterm 25 | csprng 26 | cst 27 | deref 28 | endwin 29 | envs 30 | eprint 31 | eprintln 32 | flate 33 | fmt 34 | getch 35 | getgid 36 | getmouse 37 | getuid 38 | gid 39 | glutin 40 | ident 41 | initscr 42 | isnt 43 | iters 44 | itertools 45 | izip 46 | lc 47 | leaveok 48 | lockfile 49 | macos 50 | maplit 51 | mevent 52 | millis 53 | mmask 54 | mockall 55 | mousemask 56 | mpsc 57 | multizip 58 | mut 59 | mv 60 | ncurses 61 | noecho 62 | ntapi 63 | oneshot 64 | pathdiff 65 | peekable 66 | println 67 | printw 68 | prng 69 | rfind 70 | rmatch 71 | rmatches 72 | rng 73 | rngs 74 | rsplit 75 | rsplitn 76 | rustc 77 | rustls 78 | rw 79 | scrollok 80 | seedable 81 | serde 82 | setgid 83 | setlocale 84 | setuid 85 | splitn 86 | stdscr 87 | structopt 88 | tempdir 89 | tempfile 90 | termion 91 | thiserror 92 | tokio 93 | tui 94 | valico 95 | vec 96 | walkdir 97 | writeln 98 | -------------------------------------------------------------------------------- /sample/sample.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // This is a C++ sample header 16 | 17 | #include "project_file.h" 18 | #include 19 | 20 | // comment with \ 21 | a line continuation. 22 | override a 23 | 2323ull a 24 | 2422u a 25 | 3.3 a 26 | 3.4f a 27 | 5.3x a 28 | 2.5d a 29 | .3 a 30 | .3f a 31 | 3.d a 32 | 3.f a 33 | 34 | namespace sample { 35 | 36 | #if defined(foo) && \ 37 | defined(bar) 38 | // a comment. 39 | #endif 40 | 41 | enum Blah { 42 | zero, 43 | one, 44 | two 45 | }; 46 | 47 | void int bool goto sizeof char double case const switch typedef bool 48 | 49 | constexpr char string[] = R"foo( 50 | foo: "5 apples", R"(carrot)" 51 | bar: "6 bananas", 52 | a lone " 53 | )foo"; 54 | 55 | 56 | /** 57 | * A multi-line 58 | * comment. 59 | */ 60 | int GetInt(const char* string) { 61 | return 54; 62 | } 63 | 64 | class Sample 65 | { 66 | public: 67 | Sample(double param): member_var_(param) {} 68 | 69 | void thing() { 70 | std::out << "thing 234\"32 (class) void" << " 'blah'." << this.member_var_; 71 | } 72 | 73 | private: 74 | double member_var_; 75 | }; 76 | 77 | } // namespace sample -------------------------------------------------------------------------------- /rust/src/prefs.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //use std::io::Write; 16 | use std::collections::HashMap; 17 | 18 | pub type PrefMap = HashMap; 19 | 20 | #[derive(Debug)] 21 | pub struct Prefs { 22 | pub prefs_directory: String, 23 | pub color8: PrefMap, 24 | pub color16: PrefMap, 25 | pub color256: PrefMap, 26 | //pub color: Option, 27 | //color: Option<&'a PrefMap>, 28 | pub editor: PrefMap, 29 | pub dev_test: PrefMap, 30 | pub palette: PrefMap, 31 | pub startup: PrefMap, 32 | pub status: PrefMap, 33 | pub user_data: PrefMap, 34 | } 35 | 36 | impl Prefs { 37 | pub fn new() -> Prefs { 38 | Prefs { 39 | prefs_directory: "~/.ci_edit/prefs/".to_string(), 40 | color8: PrefMap::new(), 41 | color16: PrefMap::new(), 42 | color256: PrefMap::new(), 43 | //color: None, 44 | editor: PrefMap::new(), 45 | dev_test: PrefMap::new(), 46 | palette: PrefMap::new(), 47 | startup: PrefMap::new(), 48 | status: PrefMap::new(), 49 | user_data: PrefMap::new(), 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/unit_test_regex.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | # import re 20 | import unittest 21 | 22 | import app.regex 23 | 24 | 25 | class RegexTestCases(unittest.TestCase): 26 | def test_common_numbers(self): 27 | def test_number(strInput, reg): 28 | sre = app.regex.kReNumbers.search(strInput) 29 | if sre is None: 30 | self.assertEqual(sre, reg) 31 | return 32 | self.assertEqual(reg, sre.regs[0]) 33 | 34 | test_number("quick", None) 35 | test_number("0342", (0, 4)) 36 | test_number("2342", (0, 4)) 37 | test_number("0x42", (0, 4)) 38 | test_number("0x0", (0, 3)) 39 | test_number(".2342", (0, 5)) 40 | test_number("2.342", (0, 5)) 41 | test_number("23.42", (0, 5)) 42 | test_number("234.2", (0, 5)) 43 | test_number("2342.", (0, 5)) 44 | test_number("23q42.", (0, 2)) 45 | test_number(" 2u ", (1, 3)) 46 | test_number(" 2U ", (1, 3)) 47 | test_number(" 2ull ", (1, 5)) 48 | test_number(" 2ULL ", (1, 5)) 49 | test_number(" 2.f ", (1, 4)) 50 | test_number(" .3f ", (1, 4)) 51 | test_number(" 4.7234e-11 ", (1, 11)) 52 | -------------------------------------------------------------------------------- /app/unit_test_misspellings.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | import curses 20 | 21 | from app.curses_util import * 22 | import app.fake_curses_testing 23 | 24 | 25 | class MisspellingsTestCases(app.fake_curses_testing.FakeCursesTestCase): 26 | def setUp(self): 27 | self.longMessage = True 28 | app.fake_curses_testing.FakeCursesTestCase.set_up(self) 29 | 30 | def test_highlight_misspellings(self): 31 | # self.set_movie_mode(True) 32 | self.run_with_fake_inputs( 33 | [ 34 | self.display_check(0, 0, [u" ci "]), 35 | self.cursor_check(2, 7), 36 | self.write_text(u"test asdf orange"), 37 | self.selection_check(0, 16, 0, 0, 0), 38 | self.display_check_style( 39 | 2, 7, 1, len(u"test "), self.prg.color.get(u"text", 0) 40 | ), 41 | self.display_check_style( 42 | 2, 12, 1, len(u"asdf"), self.prg.color.get(u"misspelling", 0) 43 | ), 44 | self.display_check_style( 45 | 2, 16, 1, len(u" orange"), self.prg.color.get(u"text", 0) 46 | ), 47 | CTRL_Q, 48 | u"n", 49 | ] 50 | ) 51 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # TODO(dschuyler): !/usr/bin/python -O 3 | 4 | # Copyright 2019 Google Inc. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from __future__ import absolute_import 19 | from __future__ import division 20 | from __future__ import print_function 21 | 22 | from setuptools import setup 23 | from setuptools import find_packages 24 | from datetime import datetime 25 | import io 26 | import os 27 | 28 | here = os.path.abspath(os.path.dirname(__file__)) 29 | 30 | 31 | def get_long_description(): 32 | # Read the long-description from a file. 33 | with io.open(os.path.join(here, "readme.md"), encoding="utf-8") as f: 34 | return "\n" + f.read() 35 | 36 | 37 | setup( 38 | name="ci_edit", 39 | version=datetime.strftime(datetime.today(), "%Y%m%d"), 40 | description="A terminal text editor with mouse support and ctrl+Q to quit.", 41 | long_description=get_long_description(), 42 | long_description_content_type="text/markdown", 43 | maintainer="Dave Schuyler", 44 | maintainer_email="dschuyler@chromium.org", 45 | url="https://github.com/google/ci_edit", 46 | classifiers=[ 47 | "Programming Language :: Python :: 3", 48 | "Environment :: Console", 49 | "Environment :: Console :: Curses", 50 | "License :: OSI Approved :: Apache Software License", 51 | "Topic :: Text Editors", 52 | ], 53 | packages=find_packages(), 54 | scripts=["ci.py"], 55 | license="Apache 2.0", 56 | ) 57 | -------------------------------------------------------------------------------- /sample/sample.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // This is a C++ sample file 16 | 17 | #include "project_file.h" 18 | #include "sample.h" 19 | #include 20 | 21 | // This define used to break (the < tripped up the parser). 22 | #define blue red // 1 < 2 23 | // This should be a comment 24 | 25 | "hello" 26 | #ifdef SOME_FLAG 27 | "%s and\n %-3i or\r %u with %zu float %3.12fend" 28 | #else 29 | #endif 30 | 31 | #if 0 32 | #elif 5 33 | #endif 34 | 35 | // comment with \ 36 | a line continuation. 37 | override a 38 | 2323ull a 39 | 2422u a 40 | 3.3 a 41 | 3.4f a 42 | 5.3x a 43 | 2.5d a 44 | .3 a 45 | .3f a 46 | 3.d a 47 | 3.f a 48 | 49 | (2323ull a 50 | 51 | namespace sample { 52 | 53 | #if defined(foo) && \ 54 | defined(bar) 55 | // a comment. 56 | #endif 57 | 58 | enum Blah { 59 | zero, 60 | one, 61 | two 62 | }; 63 | 64 | void int bool goto sizeof char double case const switch typedef bool 65 | 66 | constexpr char string[] = R"foo( 67 | foo: "5 apples", R"(carrot)" 68 | bar: "6 bananas", 69 | a lone " 70 | )foo"; 71 | 72 | 73 | /** 74 | * A multi-line 75 | * comment. 76 | */ 77 | int GetInt(const char* string) { 78 | return 54; 79 | } 80 | 81 | class Sample 82 | { 83 | public: 84 | Sample(double param): member_var_(param) {} 85 | 86 | void thing() { 87 | std::out << "thing 234\"32 (class) void" << " 'blah'." << this.member_var_; 88 | } 89 | 90 | private: 91 | double member_var_; 92 | }; 93 | 94 | } // namespace sample -------------------------------------------------------------------------------- /app/profile.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | import time 20 | 21 | profiles = {} 22 | 23 | 24 | def start(): 25 | return time.time() 26 | 27 | 28 | def current(key, value): 29 | profiles[key] = value 30 | 31 | 32 | def highest(key, value): 33 | if value > profiles.get(key): 34 | profiles[key] = value 35 | 36 | 37 | def lowest(key, value): 38 | if value < profiles.get(key, value): 39 | profiles[key] = value 40 | 41 | 42 | def highest_delta(key, startTime): 43 | delta = time.time() - startTime 44 | if delta > profiles.get(key): 45 | profiles[key] = delta 46 | 47 | 48 | def running_delta(key, startTime): 49 | delta = time.time() - startTime 50 | bleed = 0.501 51 | profiles[key] = delta * bleed + profiles.get(key, delta) * (1 - bleed) 52 | 53 | 54 | def results(): 55 | return "one\ntwo\nthree" 56 | 57 | 58 | # ---------------------------- 59 | # TODO(dschuyler): consider moving this python profile code out of this file. 60 | import app.log 61 | import cProfile 62 | import pstats 63 | import io 64 | 65 | 66 | def begin_python_profile(): 67 | profile = cProfile.Profile() 68 | profile.enable() 69 | return profile 70 | 71 | 72 | def end_python_profile(profile): 73 | profile.disable() 74 | output = io.StringIO.StringIO() 75 | stats = pstats.Stats(profile, stream=output).sort_stats("cumulative") 76 | stats.print_stats() 77 | app.log.info(output.getvalue()) 78 | -------------------------------------------------------------------------------- /app/clipboard.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | try: 20 | unicode 21 | except NameError: 22 | unicode = str 23 | unichr = chr 24 | 25 | import third_party.pyperclip as clipboard 26 | 27 | import app.config 28 | 29 | 30 | class Clipboard: 31 | def __init__(self): 32 | self._clipList = [] 33 | self.set_os_handlers(clipboard.copy, clipboard.paste) 34 | 35 | def copy(self, text): 36 | """Add text onto clipList. Empty |text| is not stored.""" 37 | if app.config.strict_debug: 38 | assert isinstance(text, unicode), type(text) 39 | if text and len(text): 40 | self._clipList.append(text) 41 | if self._copy: 42 | self._copy(text) 43 | 44 | def paste(self, clipIndex=None): 45 | """Fetch top of clipList; or clip at index |clipIndex|. The |clipIndex| 46 | will wrap around if it's larger than the clipList length.""" 47 | if app.config.strict_debug: 48 | assert clipIndex is None or isinstance(clipIndex, int) 49 | if clipIndex is None: 50 | osClip = self._paste and self._paste() 51 | if osClip: 52 | return osClip 53 | # Get the top of the clipList instead. 54 | clipIndex = -1 55 | if len(self._clipList): 56 | return self._clipList[clipIndex % len(self._clipList)] 57 | return None 58 | 59 | def set_os_handlers(self, copy, paste): 60 | self._copy = copy 61 | self._paste = paste 62 | -------------------------------------------------------------------------------- /tools/rename_code.py: -------------------------------------------------------------------------------- 1 | #!/bin/env python3 2 | 3 | import os 4 | import re 5 | import sys 6 | 7 | if len(sys.argv) < 2: # or sys.argv[1] == "--help": 8 | print("rename_code.py ") 9 | print("Update python code to new style.") 10 | sys.exit(0) 11 | 12 | old_names = set() 13 | class_names = set() 14 | for (dir, dirs, files) in os.walk(sys.argv[1]): 15 | if dir == ".git": 16 | continue 17 | for file in files: 18 | if not file.endswith(".py"): 19 | continue 20 | path = os.path.join(dir, file) 21 | print("-----", path) 22 | with open(path) as f: 23 | data = f.read() 24 | for i in re.finditer(r"\bdef\s+(\w+)", data): 25 | name = i.group(1) 26 | if re.search(r"[A-Z]", name): 27 | print(":", name) 28 | old_names.add(name) 29 | for i in re.finditer(r"\bclass\s+(\w+)", data): 30 | name = i.group(1) 31 | class_names.add(name) 32 | # print("old_names:", old_names) 33 | # print("class_names:", class_names) 34 | for i in class_names: 35 | if i in old_names: 36 | print(i, "is also a class name") 37 | old_names.remove(i) 38 | # print("old_names:", old_names) 39 | find_old_name = re.compile(r"(\b" + r"\b|\b".join(old_names) + r")\b") 40 | for (dir, dirs, files) in os.walk(sys.argv[1]): 41 | if dir == ".git": 42 | continue 43 | for file in files: 44 | if not file.endswith(".py"): 45 | continue 46 | if file == "rename_code.py": 47 | continue 48 | path = os.path.join(dir, file) 49 | print("-----", path) 50 | with open(path, "r+") as f: 51 | data = find_old_name.sub( 52 | lambda x: re.sub( 53 | "([A-Z])", lambda n: "_" + n.group(1).lower(), x.group(1) 54 | ), 55 | f.read(), 56 | ) 57 | f.seek(0) 58 | if path.find("/unit_test_") != -1: 59 | print("----- [correcting] ", path) 60 | data = re.sub(r"\bdef set_up\b", "def setUp", data) 61 | data = re.sub(r"\bdef tear_down\b", "def tearDown", data) 62 | f.write(data) 63 | -------------------------------------------------------------------------------- /ci.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # TODO(dschuyler): !/usr/bin/python -O 3 | 4 | # Copyright 2016 Google Inc. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from __future__ import absolute_import 19 | from __future__ import division 20 | from __future__ import print_function 21 | 22 | import sys 23 | 24 | 25 | def version_check(): 26 | if sys.version_info[0] <= 2: 27 | msg = """ 28 | 29 | Hi, 30 | 31 | Are you able to use Python 3? Please use ci_edit with Python 3. Doing so will 32 | avoid this message. 33 | 34 | In the future ci_edit will be dropping support for Python 2. 35 | 36 | I/we are not able to 'see' how many users are currently using Python 2. This is 37 | for your safety/privacy. The ci_edit program is not permitted to send 38 | information about you back to us. So for us to know if you need Python 2 support 39 | we need you to tell us. If you need Python 2 support please report (make a 40 | comment) here: https://github.com/google/ci_edit/issues/205 41 | 42 | In the near term, you can also avoid this message by passing --p2 on the command 43 | line when running ci_edit. 44 | 45 | """ 46 | print(msg) 47 | sys.exit(1) 48 | 49 | 50 | if __name__ == "__main__": 51 | args = sys.argv 52 | if "--test" in args: 53 | import unit_tests 54 | 55 | args.remove("--test") 56 | sys.exit(unit_tests.parse_arg_list(args)) 57 | if "--p2" not in args: 58 | version_check() 59 | else: 60 | args.remove("--p2") 61 | if "--strict" in args: 62 | import app.config 63 | 64 | args.remove("--strict") 65 | app.config.strict_debug = True 66 | import app.ci_program 67 | 68 | app.ci_program.run_ci() 69 | -------------------------------------------------------------------------------- /sample/sample.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 53 | 59 | 60 | 61 |
This closing br is an error.
62 |
This closing hr is an error. 63 | This closing img is an error. 64 | This closing input is an error. 65 | 67 | 69 | 70 | 71 | /* Not an HTML comment. */ 72 | // Not a comment 73 | Some non-keywords if or while or for or function 74 | 75 | special & or &0x33; or   76 | normal \n \r 77 | 78 | -------------------------------------------------------------------------------- /app/unit_test_prefs.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | import unittest 20 | 21 | from app.curses_util import * 22 | import app.fake_curses_testing 23 | import app.prefs 24 | 25 | 26 | class PrefsTestCases(app.fake_curses_testing.FakeCursesTestCase): 27 | def setUp(self): 28 | self.longMessage = True 29 | app.fake_curses_testing.FakeCursesTestCase.set_up(self) 30 | self.prefs = app.prefs.Prefs() 31 | 32 | def test_default_prefs(self): 33 | self.run_with_fake_inputs( 34 | [ 35 | self.pref_check(u"editor", u"saveUndo", True), 36 | CTRL_Q, 37 | ] 38 | ) 39 | 40 | def test_get_file_type(self): 41 | get_file_type = self.prefs.get_file_type 42 | self.assertEqual(get_file_type(""), "words") 43 | self.assertEqual(get_file_type("a.py"), "py") 44 | self.assertEqual(get_file_type("a.cc"), "cpp") 45 | self.assertEqual(get_file_type("a.c"), "c") 46 | self.assertEqual(get_file_type("a.h"), "cpp") 47 | self.assertEqual(get_file_type("Makefile"), "make") 48 | self.assertEqual(get_file_type("BUILD"), "bazel") 49 | self.assertEqual(get_file_type("build"), "words") 50 | self.assertEqual(get_file_type("BUILD.gn"), "gn") 51 | self.assertEqual(get_file_type("a.md"), "md") 52 | 53 | def test_tabs_to_spaces(self): 54 | tabs_to_spaces = self.prefs.tabs_to_spaces 55 | self.assertEqual(tabs_to_spaces("words"), True) 56 | self.assertEqual(tabs_to_spaces("make"), False) 57 | self.assertEqual(tabs_to_spaces("cpp"), True) 58 | self.assertEqual(tabs_to_spaces(None), False) 59 | self.assertEqual(tabs_to_spaces("foo"), None) 60 | -------------------------------------------------------------------------------- /app/string.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | try: 20 | unicode 21 | except NameError: 22 | unicode = str 23 | unichr = chr 24 | 25 | import app.config 26 | 27 | ENCODE = { 28 | u"\\": u"\\\\", 29 | u"\a": u"\\a", 30 | u"\b": u"\\b", 31 | u"\f": u"\\f", 32 | u"\n": u"\\n", 33 | u"\r": u"\\r", 34 | u"\t": u"\\t", 35 | u"\v": u"\\v", 36 | u"\x7f": u"\\x7f", 37 | } 38 | 39 | DECODE = { 40 | u"\\": u"\\", 41 | u"a": u"\a", 42 | u"b": u"\b", 43 | u"f": u"\f", 44 | u"n": u"\n", 45 | u"r": u"\r", 46 | u"t": u"\t", 47 | u"v": u"\v", 48 | } 49 | 50 | 51 | def path_encode(path): 52 | if app.config.strict_debug: 53 | assert isinstance(path, unicode), repr(path) 54 | out = u"" 55 | for i in range(len(path)): 56 | c = path[i] 57 | ord_c = ord(c) 58 | t = ENCODE.get(c) 59 | if t is not None: 60 | c = t 61 | elif ord_c < 32: 62 | c = u"\\x%02x" % (ord_c,) 63 | out += c 64 | return out 65 | 66 | 67 | def path_decode(path): 68 | if app.config.strict_debug: 69 | assert isinstance(path, unicode) 70 | out = u"" 71 | limit = len(path) 72 | i = 0 73 | while i < limit: 74 | c = path[i] 75 | i += 1 76 | if c == u"\\": 77 | if i >= len(path): 78 | out += u"\\" 79 | break 80 | c = path[i] 81 | i += 1 82 | if c == u"x": 83 | c = unichr(path[i - 1 : i + 3]) 84 | elif c == u"u" or c == u"o": 85 | c = unichr(path[i - 1 : i + 5]) 86 | elif c == u"U": 87 | c = unichr(path[i - 1 : i + 9]) 88 | else: 89 | c = DECODE.get(c, u"\\") 90 | out += c 91 | return out 92 | -------------------------------------------------------------------------------- /app/unit_test_execute_prompt.py: -------------------------------------------------------------------------------- 1 | # -*- coding: latin-1 -*- 2 | 3 | # Copyright 2018 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from __future__ import absolute_import 18 | from __future__ import division 19 | from __future__ import print_function 20 | 21 | import curses 22 | import sys 23 | 24 | from app.curses_util import * 25 | import app.fake_curses_testing 26 | 27 | 28 | class ExecutePromptTestCases(app.fake_curses_testing.FakeCursesTestCase): 29 | def setUp(self): 30 | self.longMessage = True 31 | app.fake_curses_testing.FakeCursesTestCase.set_up(self) 32 | 33 | def test_execute(self): 34 | # self.set_movie_mode(True) 35 | self.run_with_fake_inputs( 36 | [ 37 | self.display_check(-1, 0, [u" "]), 38 | CTRL_E, 39 | self.display_check(-1, 0, [u"e: "]), 40 | CTRL_J, 41 | self.display_check(-1, 0, [u" "]), 42 | CTRL_E, 43 | self.display_check(-1, 0, [u"e: "]), 44 | CTRL_J, 45 | CTRL_Q, 46 | ] 47 | ) 48 | 49 | def test_pipe_sort(self): 50 | # self.set_movie_mode(True) 51 | self.run_with_fake_inputs( 52 | [ 53 | self.write_text(u"carrot\nbanana\nbanana\napple\n"), 54 | self.display_check( 55 | 2, 56 | 7, 57 | [u"carrot ", u"banana ", u"banana ", u"apple ", u" "], 58 | ), 59 | CTRL_A, 60 | CTRL_E, 61 | self.write_text(u"|sort"), 62 | self.display_check(-1, 0, [u"e: |sort "]), 63 | CTRL_J, 64 | self.display_check( 65 | 2, 66 | 7, 67 | [u"apple ", u"banana ", u"banana ", u"carrot ", u" "], 68 | ), 69 | CTRL_Q, 70 | u"n", 71 | ] 72 | ) 73 | -------------------------------------------------------------------------------- /app/unit_test_startup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2019 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | from __future__ import absolute_import 17 | from __future__ import division 18 | from __future__ import print_function 19 | 20 | import curses 21 | import os 22 | import sys 23 | 24 | from app.curses_util import * 25 | import app.ci_program 26 | import app.fake_curses_testing 27 | 28 | kTestFile = u"#startup_test_file_with_unlikely_file_name~" 29 | 30 | 31 | class StartupTestCases(app.fake_curses_testing.FakeCursesTestCase): 32 | def setUp(self): 33 | self.longMessage = True 34 | app.fake_curses_testing.FakeCursesTestCase.set_up(self) 35 | 36 | def test_no_args(self): 37 | self.run_with_fake_inputs( 38 | [self.display_check(2, 7, [u" "]), self.cursor_check(2, 7), CTRL_Q] 39 | ) 40 | 41 | def test_one_file(self): 42 | # self.set_movie_mode(True) 43 | self.run_with_fake_inputs( 44 | [ 45 | self.display_check(2, 7, [u"// Copyright "]), 46 | self.cursor_check(2, 7), 47 | CTRL_Q, 48 | ], 49 | [sys.argv[0], self.path_to_sample(u"sample.cc")], 50 | ) 51 | 52 | def test_two_files(self): 53 | # self.set_movie_mode(True) 54 | self.run_with_fake_inputs( 55 | [ 56 | KEY_PAGE_DOWN, 57 | self.display_check(5, 7, [u"// This is a C++ sample file"]), 58 | self.cursor_check(2, 7), 59 | CTRL_W, 60 | KEY_PAGE_DOWN, 61 | self.display_check(5, 7, [u"// This is a C++ sample header"]), 62 | CTRL_Q, 63 | ], 64 | [ 65 | sys.argv[0], 66 | self.path_to_sample(u"sample.cc"), 67 | self.path_to_sample(u"sample.h"), 68 | ], 69 | ) 70 | 71 | def test_one_file_line(self): 72 | # self.set_movie_mode(True) 73 | self.run_with_fake_inputs( 74 | [ 75 | self.display_check(2, 7, [u"// distributed under the License"]), 76 | self.cursor_check(4, 7), 77 | CTRL_Q, 78 | ], 79 | [sys.argv[0], self.path_to_sample(u"sample.cc:12")], 80 | ) 81 | -------------------------------------------------------------------------------- /app/unit_test_prediction_window.py: -------------------------------------------------------------------------------- 1 | # -*- coding: latin-1 -*- 2 | 3 | # Copyright 2018 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from __future__ import absolute_import 18 | from __future__ import division 19 | from __future__ import print_function 20 | 21 | import curses 22 | import sys 23 | 24 | from app.curses_util import * 25 | import app.fake_curses_testing 26 | 27 | 28 | class PredictionWindowTestCases(app.fake_curses_testing.FakeCursesTestCase): 29 | def setUp(self): 30 | self.longMessage = True 31 | app.fake_curses_testing.FakeCursesTestCase.set_up(self) 32 | 33 | def test_prediction(self): 34 | # self.set_movie_mode(True) 35 | sys.argv = [] 36 | self.run_with_fake_inputs( 37 | [ 38 | self.display_check(0, 0, [u" ci "]), 39 | self.display_check(2, 7, [u" "]), 40 | CTRL_P, 41 | self.display_check(0, 0, [u" ci "]), 42 | self.display_check(2, 2, [u"- Type|Name "]), 43 | # self.display_check_not(3, 0, [u" open "]), 44 | self.find_text_and_click(1000, u"[x]open", curses.BUTTON1_PRESSED), 45 | self.display_check_not(3, 0, [u" open "]), 46 | self.display_check(2, 2, [u"- Type|Name "]), 47 | self.find_text_and_click(2000, u"[ ]open", curses.BUTTON1_PRESSED), 48 | # TODO(dschuyler): Look into why this fails: 49 | # self.display_check(3, 0, [" open "]), 50 | CTRL_Q, 51 | ] 52 | ) 53 | 54 | def test_save_as_to_quit(self): 55 | # self.set_movie_mode(True) 56 | sys.argv = [] 57 | self.run_with_fake_inputs( 58 | [ 59 | self.display_check(0, 0, [u" ci "]), 60 | self.display_check(2, 7, [u" "]), 61 | ord("a"), 62 | self.display_check(2, 7, [u"a "]), 63 | CTRL_S, 64 | self.display_check(0, 0, [u" ci Save File As"]), 65 | CTRL_Q, 66 | self.display_check(0, 0, [u" ci "]), 67 | self.display_check(-2, 0, [u" "]), 68 | CTRL_Q, 69 | ord("n"), 70 | ] 71 | ) 72 | -------------------------------------------------------------------------------- /app/vi_editor.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """Key bindings for the vi-like editor.""" 15 | 16 | from __future__ import absolute_import 17 | from __future__ import division 18 | from __future__ import print_function 19 | 20 | import curses 21 | import curses.ascii 22 | import os 23 | import re 24 | 25 | from app.curses_util import * 26 | import app.controller 27 | import app.log 28 | import app.text_buffer 29 | 30 | 31 | class ViEdit(app.controller.Controller): 32 | """Vi is a common Unix editor. This mapping supports some common vi/vim 33 | commands.""" 34 | 35 | def __init__(self, view): 36 | app.controller.Controller.__init__(self, view, "ViEdit") 37 | self.commandDefault = None 38 | 39 | def set_text_buffer(self, textBuffer): 40 | app.controller.Controller.set_text_buffer(self, textBuffer) 41 | normalCommandSet = { 42 | ord("^"): textBuffer.cursor_start_of_line, 43 | ord("$"): textBuffer.cursor_end_of_line, 44 | ord("h"): textBuffer.cursor_left, 45 | ord("i"): self.switch_to_command_set_insert, 46 | ord("j"): textBuffer.cursor_down, 47 | ord("k"): textBuffer.cursor_up, 48 | ord("l"): textBuffer.cursor_right, 49 | } 50 | self.commandSet = normalCommandSet 51 | self.commandSet_Insert = { 52 | curses.ascii.ESC: self.switch_to_command_set_normal, 53 | } 54 | self.commandDefault = self.textBuffer.insert_printable 55 | 56 | def info(self): 57 | app.log.info("ViEdit Command set main") 58 | app.log.info(repr(self)) 59 | 60 | def focus(self): 61 | app.log.info("VimEdit.focus") 62 | if not self.commandDefault: 63 | self.commandDefault = self.textBuffer.no_op 64 | self.commandSet = self.commandSet_Normal 65 | 66 | def on_change(self): 67 | pass 68 | 69 | def switch_to_command_set_insert(self, ignored=1): 70 | app.log.info("insert mode") 71 | self.commandDefault = self.textBuffer.insert_printable 72 | self.commandSet = self.commandSet_Insert 73 | 74 | def switch_to_command_set_normal(self, ignored=1): 75 | app.log.info("normal mode") 76 | self.commandDefault = self.textBuffer.no_op 77 | self.commandSet = self.commandSet_Normal 78 | -------------------------------------------------------------------------------- /app/dictionary.chromium.words: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | # Chromium (May be specific to Chromium development) 17 | # May of these are not real words or correct spellings. 18 | accname 19 | ais 20 | ansa 21 | ansb 22 | appcache 23 | appcaches 24 | appmenu 25 | arraysize 26 | asan 27 | atlbase 28 | atlwin 29 | autocollapse 30 | autocompleted 31 | autocompletion 32 | autolaunch 33 | axs 34 | backend 35 | bolded 36 | bolding 37 | breakpad 38 | browsertest 39 | buildflag 40 | buildflags 41 | callstack 42 | cbd 43 | cflags 44 | checkboxes 45 | chromevox 46 | clientdata 47 | codereview 48 | coord 49 | coords 50 | cpplint 51 | cras 52 | cros 53 | crosh 54 | cryptohome 55 | cws 56 | darkconnect 57 | dcheck 58 | decltype 59 | declval 60 | deletability 61 | displaymode 62 | dlog 63 | doesnt 64 | dont 65 | dragdrop 66 | dsc 67 | dst 68 | du 69 | eap 70 | ef 71 | eslint 72 | ev 73 | fallthrough 74 | fieldtrialtriggered 75 | filemanager 76 | fixup 77 | focusability 78 | fullscreen 79 | futf 80 | gclient 81 | gdoc 82 | gdraw 83 | gmock 84 | gn 85 | gni 86 | goma 87 | googlesource 88 | grd 89 | gtest 90 | gtestjs 91 | gurl 92 | hardcoded 93 | harf 94 | hotword 95 | hwid 96 | infobar 97 | jstemplate 98 | keycodes 99 | lbuttonup 100 | log 101 | lso 102 | mojom 103 | mousewheel 104 | multidex 105 | multiline 106 | nacl 107 | nav 108 | navsuggest 109 | navsuggestion 110 | navsuggestions 111 | newtabpage 112 | nogncheck 113 | nolint 114 | nonslash 115 | notreached 116 | onc 117 | oobe 118 | osk 119 | otr 120 | outdent 121 | pak 122 | pcheck 123 | plog 124 | powerwash 125 | ppapi 126 | preconnect 127 | preconnectable 128 | prerendering 129 | presubmit 130 | protobuf 131 | pylint 132 | rappor 133 | relevances 134 | remora 135 | rendertext 136 | rlz 137 | rtlui 138 | safebrowsing 139 | scoper 140 | scrollview 141 | sel 142 | sideload 143 | sideloaded 144 | spdy 145 | stringprintf 146 | subtypeid 147 | suggestdetail 148 | suggestrelevance 149 | suggesttype 150 | tabrestore 151 | tabstrip 152 | tbr 153 | textfield 154 | tooltips 155 | triggerer 156 | triggerers 157 | tryserver 158 | uitest 159 | ukm 160 | uma 161 | unittest 162 | unittests 163 | uwyt 164 | verbatimrelevance 165 | vis 166 | vlog 167 | vox 168 | vpd 169 | webdata 170 | webrtc 171 | webstore 172 | wildcard 173 | wrl 174 | xtb 175 | -------------------------------------------------------------------------------- /app/regex.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | import re 20 | 21 | 22 | def join_re_list(reList): 23 | return r"(" + r")|(".join(reList) + r")" 24 | 25 | 26 | def join_re_word_list(reList): 27 | return r"(\b" + r"\b)|(\b".join(reList) + r"\b)" 28 | 29 | 30 | kNonMatchingRegex = r"^\b$" 31 | kReNonMatching = re.compile(kNonMatchingRegex) 32 | 33 | # Beware, to include a ] in a set, it should be the first character in the set. 34 | # So, the first ] does not close the set and the second [ does not open a set. 35 | # The set of characters is ]{}()[. 36 | kBracketsRegex = u"[]{}()[]" 37 | kReBrackets = re.compile(kBracketsRegex) 38 | 39 | kReComments = re.compile("(?:#|//).*$|/\*.*?\*/|") 40 | 41 | kEndSpacesRegex = r"\s+$" 42 | kReEndSpaces = re.compile(kEndSpacesRegex) 43 | 44 | kReStrings = re.compile( 45 | r"(\"\"\".*?(?' may be appended. If the file doesn't exist as-is, try 38 | removing those decorations, and if that exists use that path instead. 39 | 40 | Returns: (fullPath, openToRow, openToCol) 41 | """ 42 | if app.config.strict_debug: 43 | assert isinstance(path, unicode) 44 | assert projectDir is None or isinstance(projectDir, unicode) 45 | openToRow = None 46 | openToColumn = None 47 | if os.path.isfile(path): # or os.path.isdir(os.path.dirname(path)): 48 | return path, openToRow, openToColumn 49 | pieces = path.split(u":") 50 | if pieces[-1] == u"": 51 | if len(pieces) == 3: 52 | try: 53 | openToRow = int(pieces[1]) - 1 54 | except ValueError: 55 | pass 56 | elif len(pieces) == 4: 57 | try: 58 | openToRow = int(pieces[1]) - 1 59 | openToColumn = int(pieces[2]) - 1 60 | except ValueError: 61 | pass 62 | else: 63 | if len(pieces) == 2: 64 | try: 65 | openToRow = int(pieces[1]) - 1 66 | except ValueError: 67 | pass 68 | elif len(pieces) == 3: 69 | try: 70 | openToRow = int(pieces[1]) - 1 71 | openToColumn = int(pieces[2]) - 1 72 | except ValueError: 73 | pass 74 | if openToRow is not None: 75 | path = pieces[0] 76 | if len(path) > 2: # and not os.path.isdir(path[:2]): 77 | if projectDir is not None and path.startswith(u"//"): 78 | path = projectDir + path[1:] 79 | elif path[1] == u"/": 80 | if os.path.isfile(path[2:]): 81 | path = path[2:] 82 | return path, openToRow, openToColumn 83 | 84 | 85 | def expand_full_path(path): 86 | return os.path.abspath(os.path.expanduser(os.path.expandvars(path))) 87 | -------------------------------------------------------------------------------- /test_fake/curses/constants.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | # These constants have specific values. 20 | COLORS = 256 21 | ERR = -1 # ERR is normally -1. 22 | 23 | # These constants have arbitrary values. 24 | KEY_ALT_A = 0 # todo 25 | KEY_ALT_B = 1 # todo 26 | KEY_ALT_C = 2 # todo 27 | KEY_ALT_LEFT = (91, 49, 59, 57, 68) 28 | KEY_ALT_RIGHT = (91, 49, 59, 57, 67) 29 | KEY_ALT_S = 5 # todo 30 | KEY_ALT_SHIFT_LEFT = 6 # todo 31 | KEY_ALT_SHIFT_RIGHT = 7 # todo 32 | KEY_BACKSPACE = 8 # todo 33 | KEY_BACKSPACE1 = 9 # todo 34 | KEY_BACKSPACE2 = 10 # todo 35 | KEY_BACKSPACE3 = 11 # todo 36 | KEY_BTAB = 12 # todo 37 | KEY_CTRL_DOWN = 13 # todo 38 | KEY_CTRL_LEFT = 14 # todo 39 | KEY_CTRL_RIGHT = 15 # todo 40 | KEY_CTRL_SHIFT_DOWN = 16 # todo 41 | KEY_CTRL_SHIFT_LEFT = 17 # todo 42 | KEY_CTRL_SHIFT_RIGHT = 18 # todo 43 | KEY_CTRL_SHIFT_UP = 19 # todo 44 | KEY_CTRL_UP = 20 # todo 45 | KEY_DC = 21 # todo 46 | KEY_DELETE = 22 # todo 47 | KEY_DOWN = 23 # todo 48 | KEY_END = 24 # todo 49 | KEY_ESCAPE = 27 50 | KEY_F1 = 265 51 | KEY_F10 = 274 52 | KEY_F13 = 28 # todo 53 | KEY_F14 = 278 54 | KEY_F15 = 30 # todo 55 | KEY_F16 = 31 # todo 56 | KEY_F17 = 32 # todo 57 | KEY_F18 = 33 # todo 58 | KEY_F19 = 34 # todo 59 | KEY_F2 = 266 60 | KEY_F20 = 36 # todo 61 | KEY_F21 = 37 # todo 62 | KEY_F22 = 38 # todo 63 | KEY_F3 = 267 64 | KEY_F4 = 268 65 | KEY_F5 = 41 # todo 66 | KEY_F6 = 42 # todo 67 | KEY_F7 = 43 # todo 68 | KEY_F8 = 44 # todo 69 | KEY_F9 = 45 # todo 70 | KEY_HOME = 46 # todo 71 | KEY_LEFT = 260 72 | KEY_MOUSE = 409 73 | KEY_NPAGE = 49 # todo 74 | KEY_PAGE_DOWN = 50 # todo 75 | KEY_PAGE_UP = 51 # todo 76 | KEY_PPAGE = 52 # todo 77 | KEY_RESIZE = 53 # todo 78 | KEY_RESIZE = 54 # todo 79 | KEY_RIGHT = 261 # todo 80 | KEY_SF = 56 # todo 81 | KEY_SHIFT_DOWN = 57 # todo 82 | KEY_SHIFT_F2 = 58 # todo 83 | KEY_SHIFT_F3 = 59 # todo 84 | KEY_SHIFT_LEFT = 60 # todo 85 | KEY_SHIFT_RIGHT = 61 # todo 86 | KEY_SHIFT_UP = 62 # todo 87 | KEY_SLEFT = 63 # todo 88 | KEY_SNEXT = 64 # todo 89 | KEY_SPREVIOUS = 65 # todo 90 | KEY_SR = 66 # todo 91 | KEY_SRIGHT = 67 # todo 92 | KEY_UP = 68 # todo 93 | KEY_SEND = 69 # todo 94 | KEY_SHOME = 70 # todo 95 | 96 | A_BOLD = 1 << 15 97 | A_REVERSE = 1 << 16 98 | BUTTON1_CLICKED = 4 99 | BUTTON1_DOUBLE_CLICKED = 8 100 | BUTTON1_PRESSED = 2 101 | BUTTON1_RELEASED = 1 102 | BUTTON2_CLICKED = 256 103 | BUTTON2_DOUBLE_CLICKED = 512 104 | BUTTON2_PRESSED = 128 105 | BUTTON2_RELEASED = 64 106 | BUTTON3_CLICKED = 16384 107 | BUTTON3_DOUBLE_CLICKED = 32768 108 | BUTTON3_PRESSED = 8192 109 | BUTTON3_RELEASED = 4096 110 | BUTTON4_CLICKED = 1048576 111 | BUTTON4_DOUBLE_CLICKED = 2097152 112 | BUTTON4_PRESSED = 524288 113 | BUTTON4_RELEASED = 262144 114 | BUTTON_ALT = 67108864 115 | BUTTON_CTRL = 16777216 116 | BUTTON_SHIFT = 33554432 117 | REPORT_MOUSE_POSITION = 134217728 118 | -------------------------------------------------------------------------------- /app/dictionary.fuchsia.words: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # This is a list of non-English words that are in the open source Fuchsia OS. 16 | abigen 17 | accel 18 | addrs 19 | amberctl 20 | apic 21 | appmgr 22 | arches 23 | arraysize 24 | artifactory 25 | asan 26 | aspace 27 | autogenerated 28 | bc 29 | binfo 30 | blk 31 | blobfs 32 | bootfs 33 | breakpoint 34 | bti 35 | cdecls 36 | chdir 37 | chrealm 38 | classname 39 | cmc 40 | cmdline 41 | cml 42 | cmx 43 | codegen 44 | conns 45 | contig 46 | countof 47 | cts 48 | ctu 49 | curr 50 | dassert 51 | dcheck 52 | ddktl 53 | decodable 54 | depfile 55 | devmgr 56 | devshell 57 | disp 58 | dl 59 | dso 60 | embedders 61 | emebbing 62 | eoi 63 | eport 64 | eproto 65 | errorf 66 | eventpair 67 | exceptionate 68 | excp 69 | executability 70 | fastboot 71 | fasync 72 | fbl 73 | fconfig 74 | fctl 75 | ffx 76 | fgsutil 77 | fidl 78 | fidlc 79 | fidlcat 80 | fidlgen 81 | fini 82 | finspect 83 | fizzbuzz 84 | fms 85 | fremote 86 | fsl 87 | fssh 88 | fvd 89 | fvdl 90 | fvm 91 | fxb 92 | fxbug 93 | fxdev 94 | fxfs 95 | fxl 96 | fzl 97 | ga 98 | gmock 99 | gn 100 | gni 101 | googlesource 102 | googletest 103 | gpaddr 104 | grpcwebproxy 105 | gsi 106 | gtest 107 | gzipped 108 | hwinfo 109 | idk 110 | idx 111 | inode 112 | inodes 113 | ints 114 | iommu 115 | iovec 116 | ipi 117 | ipis 118 | iquery 119 | je 120 | kcounter 121 | kcounters 122 | killall 123 | kmem 124 | koid 125 | koids 126 | kstats 127 | ktl 128 | ktrace 129 | libasync 130 | libfidl 131 | libfit 132 | libobject 133 | libsyscalls 134 | libzircon 135 | lifecycle 136 | lkthread 137 | lockdep 138 | logf 139 | lowmem 140 | lsan 141 | ltrace 142 | ltracef 143 | lx 144 | mali 145 | matred 146 | mbx 147 | memgraph 148 | merkleroot 149 | minfs 150 | minidump 151 | mins 152 | mmio 153 | msd 154 | mtx 155 | nanos 156 | nanosleep 157 | netaddr 158 | netboot 159 | netcp 160 | netls 161 | netmask 162 | netprotocol 163 | netruncmd 164 | ngunwind 165 | notreached 166 | nx 167 | overnet 168 | paddr 169 | pbm 170 | pbms 171 | pbtool 172 | physmap 173 | pkgctl 174 | pkgfs 175 | pkgsvr 176 | pmi 177 | pmm 178 | pmt 179 | preemptiveness 180 | preinstall 181 | priv 182 | procs 183 | protobuf 184 | protoc 185 | protos 186 | psutils 187 | pyproto 188 | ramdisk 189 | realtime 190 | refcount 191 | rfcs 192 | rng 193 | sessionctl 194 | singlethreaded 195 | sm 196 | smbug 197 | spinlock 198 | srv 199 | starnix 200 | sui 201 | svc 202 | swd 203 | syscalls 204 | sysinfo 205 | sysmem 206 | sysmgr 207 | sysroot 208 | termina 209 | testcase 210 | testonly 211 | toolchain 212 | toolchains 213 | tremplin 214 | tuf 215 | txid 216 | ua 217 | ulib 218 | unittest 219 | unittests 220 | upscript 221 | userboot 222 | userspace 223 | vaddr 224 | vbmeta 225 | vboot 226 | vdl 227 | vdso 228 | vec 229 | versioned 230 | vfx 231 | virtio 232 | vlog 233 | vlogs 234 | vmaps 235 | vmar 236 | vmars 237 | vmm 238 | vmos 239 | vsock 240 | waitfor 241 | wl 242 | wlan 243 | wordwise 244 | zbi 245 | zedboot 246 | zircona 247 | zirconb 248 | zxcpp 249 | zxdb 250 | zxlogf 251 | zxtest 252 | -------------------------------------------------------------------------------- /tools/checkSpelling.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright 2017 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from __future__ import print_function 18 | 19 | import glob 20 | import io 21 | import os 22 | import pprint 23 | import re 24 | import sys 25 | from fnmatch import fnmatch 26 | 27 | ciEditDir = os.path.dirname(os.path.dirname(__file__)) 28 | sys.path.append(ciEditDir) 29 | import app.regex 30 | import app.spelling 31 | 32 | print("checking spelling") 33 | 34 | doValues = False 35 | root = (len(sys.argv) > 1 and sys.argv[1]) or "." 36 | filePattern = (len(sys.argv) > 2 and sys.argv[2]) or "*.*" 37 | 38 | kReWords = re.compile(r"""(\w+)""") 39 | # The first group is a hack to allow upper case pluralized, e.g. URLs. 40 | kReSubwords = re.compile( 41 | r"((?:[A-Z]{2,}s\b)|(?:[A-Z][a-z]+)|(?:[A-Z]+(?![a-z]))|(?:[a-z]+))" 42 | ) 43 | 44 | kReIgnoreDirs = re.compile(r"""/\.git/""") 45 | kReIgnoreFiles = re.compile( 46 | r"""\.(pyc|pyo|png|a|jpg|tif|mp3|mp4|cpuperf|dylib|avi|so|plist|raw|webm)$""" 47 | ) 48 | kReIncludeFiles = re.compile(r"""\.(cc)$""") 49 | assert kReIgnoreDirs.search("/apple/.git/orange") 50 | assert kReIgnoreFiles.search("/apple.pyc") 51 | 52 | dictionaryList = glob.glob(os.path.join(ciEditDir, "app/dictionary.*.words")) 53 | dictionaryList = [os.path.basename(i)[11:-6] for i in dictionaryList] 54 | print(pprint.pprint(dictionaryList)) 55 | pathPrefs = [] 56 | dictionary = app.spelling.Dictionary(dictionaryList, pathPrefs) 57 | assert dictionary.is_correct(u"has", "cpp") 58 | 59 | 60 | def handle_file(fileName, unrecognizedWords): 61 | # print(fileName, end="") 62 | try: 63 | with io.open(fileName, "r") as f: 64 | data = f.read() 65 | if not data: 66 | return 67 | for sre in kReSubwords.finditer(data): 68 | # print(repr(sre.groups())) 69 | word = sre.groups()[0].lower() 70 | if not dictionary.is_correct(word, "cpp"): 71 | if word not in unrecognizedWords: 72 | print(word, end=",") 73 | unrecognizedWords.add(word) 74 | except UnicodeDecodeError: 75 | print("Error decoding:", fileName) 76 | 77 | 78 | def walk_tree(root): 79 | unrecognizedWords = set() 80 | for (dirPath, dirNames, fileNames) in os.walk(root): 81 | if kReIgnoreDirs.search(dirPath): 82 | continue 83 | for fileName in filter(lambda x: fnmatch(x, filePattern), fileNames): 84 | if kReIgnoreFiles.search(fileName): 85 | continue 86 | if kReIncludeFiles.search(fileName): 87 | handle_file(os.path.join(dirPath, fileName), unrecognizedWords) 88 | if unrecognizedWords: 89 | print("found", fileName) 90 | print(unrecognizedWords) 91 | print() 92 | return unrecognizedWords 93 | 94 | 95 | if os.path.isfile(root): 96 | print(handle_file(root)) 97 | elif os.path.isdir(root): 98 | words = sorted(walk_tree(root)) 99 | for i in words: 100 | print(i) 101 | else: 102 | print("root is not a file or directory") 103 | 104 | print("---- end ----") 105 | -------------------------------------------------------------------------------- /third_party/pyperclip/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Pyperclip 3 | 4 | A cross-platform clipboard module for Python. (only handles plain text for now) 5 | By Al Sweigart al@inventwithpython.com 6 | BSD License 7 | 8 | Usage: 9 | import pyperclip 10 | pyperclip.copy('The text to be copied to the clipboard.') 11 | spam = pyperclip.paste() 12 | 13 | if not pyperclip.copy: 14 | print("Copy functionality unavailable!") 15 | 16 | On Windows, no additional modules are needed. 17 | On Mac, the module uses pbcopy and pbpaste, which should come with the os. 18 | On Linux, install xclip or xsel via package manager. For example, in Debian: 19 | sudo apt-get install xclip 20 | 21 | Otherwise on Linux, you will need the gtk or PyQt4 modules installed. 22 | 23 | gtk and PyQt4 modules are not available for Python 3, 24 | and this module does not work with PyGObject yet. 25 | """ 26 | __version__ = "1.5.27" 27 | 28 | import platform 29 | import os 30 | import subprocess 31 | from .clipboards import ( 32 | init_osx_clipboard, 33 | init_gtk_clipboard, 34 | init_qt_clipboard, 35 | init_xclip_clipboard, 36 | init_xsel_clipboard, 37 | init_klipper_clipboard, 38 | init_no_clipboard, 39 | ) 40 | from .windows import init_windows_clipboard 41 | 42 | # `import PyQt4` sys.exit()s if DISPLAY is not in the environment. 43 | # Thus, we need to detect the presence of $DISPLAY manually 44 | # and not load PyQt4 if it is absent. 45 | HAS_DISPLAY = os.getenv("DISPLAY", False) 46 | CHECK_CMD = "where" if platform.system() == "Windows" else "which" 47 | 48 | 49 | def _executable_exists(name): 50 | return ( 51 | subprocess.call( 52 | [CHECK_CMD, name], stdout=subprocess.PIPE, stderr=subprocess.PIPE 53 | ) 54 | == 0 55 | ) 56 | 57 | 58 | def determine_clipboard(): 59 | # Determine the OS/platform and set 60 | # the copy() and paste() functions accordingly. 61 | if "cygwin" in platform.system().lower(): 62 | # FIXME: pyperclip currently does not support Cygwin, 63 | # see https://github.com/asweigart/pyperclip/issues/55 64 | pass 65 | elif os.name == "nt" or platform.system() == "Windows": 66 | return init_windows_clipboard() 67 | if os.name == "mac" or platform.system() == "Darwin": 68 | return init_osx_clipboard() 69 | if HAS_DISPLAY: 70 | # Determine which command/module is installed, if any. 71 | try: 72 | import gtk # check if gtk is installed 73 | except ImportError: 74 | pass 75 | else: 76 | return init_gtk_clipboard() 77 | 78 | try: 79 | import PyQt4 # check if PyQt4 is installed 80 | except ImportError: 81 | pass 82 | else: 83 | return init_qt_clipboard() 84 | 85 | if _executable_exists("xclip"): 86 | return init_xclip_clipboard() 87 | if _executable_exists("xsel"): 88 | return init_xsel_clipboard() 89 | if _executable_exists("klipper") and _executable_exists("qdbus"): 90 | return init_klipper_clipboard() 91 | 92 | return init_no_clipboard() 93 | 94 | 95 | def set_clipboard(clipboard): 96 | global copy, paste 97 | 98 | clipboard_types = { 99 | "osx": init_osx_clipboard, 100 | "gtk": init_gtk_clipboard, 101 | "qt": init_qt_clipboard, 102 | "xclip": init_xclip_clipboard, 103 | "xsel": init_xsel_clipboard, 104 | "klipper": init_klipper_clipboard, 105 | "windows": init_windows_clipboard, 106 | "no": init_no_clipboard, 107 | } 108 | 109 | copy, paste = clipboard_types[clipboard]() 110 | 111 | 112 | copy, paste = determine_clipboard() 113 | 114 | __all__ = ["copy", "paste"] 115 | -------------------------------------------------------------------------------- /app/line_buffer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | try: 20 | unicode 21 | except NameError: 22 | unicode = str 23 | unichr = chr 24 | 25 | import re 26 | import sys 27 | import time 28 | 29 | import app.config 30 | import app.log 31 | import app.parser 32 | 33 | 34 | class LineBuffer: 35 | def __init__(self, program): 36 | self.program = program 37 | self.isBinary = False 38 | self.parser = app.parser.Parser(program.prefs) 39 | self.parserTime = 0.0 40 | self.message = (u"New buffer", None) 41 | self.set_file_type("words") 42 | 43 | def set_file_type(self, fileType): 44 | self.fileType = fileType 45 | self.rootGrammar = self.program.prefs.get_grammar(self.fileType) 46 | # Parse from the beginning. 47 | self.parser.resumeAtRow = 0 48 | 49 | def escape_binary_chars(self, data): 50 | if app.config.strict_debug: 51 | assert isinstance(data, unicode) 52 | # Performance: in a 1000 line test it appears fastest to do some simple 53 | # .replace() calls to minimize the number of calls to parse(). 54 | data = data.replace(u"\r\n", u"\n") 55 | data = data.replace(u"\r", u"\n") 56 | if self.program.prefs.tabs_to_spaces(self.fileType): 57 | tabSize = self.program.prefs.editor.get(u"tabSize", 8) 58 | data = data.expandtabs(tabSize) 59 | 60 | def parse(sre): 61 | return u"\x01%02x" % ord(sre.groups()[0]) 62 | 63 | # data = re.sub(u'([\0-\x09\x0b-\x1f\x7f-\xff])', parse, data) 64 | data = re.sub(u"([\0-\x09\x0b-\x1f])", parse, data) 65 | return data 66 | 67 | def unescape_binary_chars(self, data): 68 | def encode(line): 69 | return chr(int(line.groups()[0], 16)) 70 | 71 | out = re.sub(u"\x01([0-9a-fA-F][0-9a-fA-F])", encode, data) 72 | if app.config.strict_debug: 73 | assert isinstance(out, unicode) 74 | return out 75 | 76 | def do_parse(self, begin, end): 77 | start = time.time() 78 | self.parser.parse( 79 | self.program.bg, self.parser.data, self.rootGrammar, begin, end 80 | ) 81 | self.debugUpperChangedRow = self.parser.resumeAtRow 82 | self.parserTime = time.time() - start 83 | 84 | def is_empty(self): 85 | return len(self.parser.data) == 0 86 | 87 | def parse_document(self): 88 | self.do_parse(self.parser.resumeAtRow, sys.maxsize) 89 | 90 | def set_message(self, *args, **kwargs): 91 | if not len(args): 92 | self.message = None 93 | # app.log.caller() 94 | return 95 | msg = str(args[0]) 96 | prior = msg 97 | for i in args[1:]: 98 | if not len(prior) or prior[-1] != "\n": 99 | msg += " " 100 | prior = str(i) 101 | msg += prior 102 | if app.config.strict_debug: 103 | app.log.caller("\n", msg) 104 | self.message = (repr(msg)[1:-1], kwargs.get("color")) 105 | -------------------------------------------------------------------------------- /app/dictionary.acronyms.words: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | # Acronyms (acronyms that match trademarks are not a challenge to said marks) 17 | absl 18 | acl 19 | acm 20 | adt 21 | afaict 22 | afaik 23 | afk 24 | ai 25 | amd 26 | ansi 27 | aot 28 | apk 29 | ar 30 | arpa 31 | ast 32 | atl 33 | awt 34 | bg 35 | bmm 36 | bmp 37 | bmps 38 | bn 39 | bnf 40 | brb 41 | brt 42 | bs 43 | bsd 44 | btw 45 | cas 46 | cb 47 | cd 48 | ceo 49 | cfo 50 | ci 51 | cisc 52 | cjk 53 | cla 54 | cmx 55 | cn 56 | cnri 57 | cpu 58 | cpus 59 | cq 60 | crd 61 | csv 62 | ctl 63 | cua 64 | da 65 | dbs 66 | ddd 67 | ddk 68 | dll 69 | dlls 70 | dmm 71 | dmms 72 | dns 73 | doa 74 | dq 75 | drm 76 | ebnf 77 | efi 78 | emmc 79 | eos 80 | et 81 | eula 82 | eulas 83 | faq 84 | faqs 85 | fc 86 | fde 87 | fdt 88 | fg 89 | fil 90 | fpu 91 | fpus 92 | fsl 93 | ftl 94 | fubar 95 | fxl 96 | fyi 97 | fyis 98 | fzl 99 | gb 100 | gbs 101 | gc 102 | gcc 103 | gcs 104 | gdb 105 | gdi 106 | gif 107 | gifs 108 | gl 109 | gmt 110 | gn 111 | gpu 112 | gpus 113 | gsm 114 | gtg 115 | gtk 116 | gu 117 | guids 118 | hal 119 | hsv 120 | html 121 | http 122 | https 123 | hu 124 | hud 125 | huds 126 | hz 127 | iana 128 | ic 129 | ico 130 | icos 131 | icu 132 | idc 133 | ide 134 | ie 135 | iec 136 | ieee 137 | ietf 138 | ifc 139 | iiuc 140 | ime 141 | imes 142 | io 143 | ipa 144 | ipc 145 | ipcs 146 | ipp 147 | ipps 148 | ips 149 | ir 150 | iso 151 | iu 152 | ivf 153 | ja 154 | jdk 155 | jedec 156 | jit 157 | jni 158 | jvm 159 | kb 160 | kbs 161 | kde 162 | kh 163 | kia 164 | ko 165 | kos 166 | kvm 167 | lcd 168 | ld 169 | lds 170 | lgtm 171 | lgtms 172 | llc 173 | lldb 174 | llvm 175 | lpd 176 | lru 177 | lsb 178 | lsbs 179 | lsd 180 | lte 181 | lto 182 | ltr 183 | ltrs 184 | lv 185 | lz 186 | mb 187 | mbs 188 | mdn 189 | mia 190 | mips 191 | mit 192 | mmx 193 | mr 194 | mru 195 | msb 196 | msbs 197 | msc 198 | msdn 199 | msvc 200 | mvc 201 | mvp 202 | mx 203 | nafta 204 | nand 205 | nasa 206 | nb 207 | ncsa 208 | nfs 209 | nic 210 | nin 211 | nl 212 | nls 213 | nmi 214 | ns 215 | nss 216 | nt 217 | ntfs 218 | ntp 219 | nv 220 | oem 221 | oobe 222 | oop 223 | os 224 | oses 225 | osrb 226 | oss 227 | osx 228 | ota 229 | otoh 230 | pb 231 | pbs 232 | pc 233 | pcie 234 | pdd 235 | pdf 236 | pdfs 237 | pdt 238 | pgo 239 | pgp 240 | php 241 | ppc 242 | ppd 243 | ps 244 | pst 245 | qa 246 | raii 247 | rc 248 | rcs 249 | rgb 250 | rgba 251 | rgbs 252 | risc 253 | rom 254 | rpcs 255 | rsa 256 | rtc 257 | rtl 258 | ru 259 | saml 260 | sde 261 | sdk 262 | sdks 263 | sec 264 | serp 265 | ses 266 | sftp 267 | sgml 268 | sgmls 269 | sha 270 | simd 271 | sk 272 | sku 273 | sl 274 | smb 275 | sms 276 | soc 277 | sp 278 | sparc 279 | sr 280 | ssd 281 | sse 282 | ssid 283 | ssl 284 | sso 285 | ssp 286 | sv 287 | svp 288 | sw 289 | swe 290 | swf 291 | sz 292 | tb 293 | tbd 294 | tc 295 | tcp 296 | te 297 | tftp 298 | tif 299 | tifs 300 | tld 301 | tlds 302 | tls 303 | toc 304 | tp 305 | tpm 306 | ttf 307 | ttfn 308 | tuf 309 | tw 310 | ty 311 | ucs 312 | udp 313 | uefi 314 | uk 315 | un 316 | uri 317 | uris 318 | url 319 | urls 320 | usa 321 | usb 322 | usbs 323 | utc 324 | utcs 325 | uuid 326 | vk 327 | vm 328 | vma 329 | vmo 330 | vmos 331 | vp 332 | vr 333 | vv 334 | wep 335 | wfh 336 | wip 337 | www 338 | wx 339 | wysiwyg 340 | xl 341 | xml 342 | xmls 343 | xmm 344 | xssi 345 | xxl 346 | xxxl 347 | xzf 348 | yaml 349 | zh 350 | zx 351 | -------------------------------------------------------------------------------- /design/find: -------------------------------------------------------------------------------- 1 | 2 | Note: these are outline notes I used to work through design issues. They 3 | probably don't make a lot of sense to another reader at the moment. My 4 | apologies. 5 | 6 | # Find UI 7 | 8 | ## What features should a find / replace tool have 9 | 10 | find (xor i.e. a radio button or dropdown selection) 11 | - all 12 | - next 13 | - prior 14 | 15 | replace (xor) 16 | - all 17 | - current 18 | - next 19 | - prior 20 | 21 | regex (boolean) 22 | match case (exact) 23 | smart cap replacement (boolean, smart means that lower case says lower case; upper case stays upper case) 24 | span lines (boolean. aka wrap) 25 | whole words (boolean, aka by word) 26 | within (as in, find within this context) 27 | - anything (same as selecting all options?) 28 | - comments (a grammar?) 29 | - code (a grammar?) 30 | - licenses (a grammar?) 31 | - selection 32 | - quoted (strings) though maybe this is a grammar 33 | - a particular grammar (like py, js, cpp) 34 | 35 | files 36 | - recursive (boolean) 37 | - where (multi-selection i.e. checkboxes) 38 | - current file 39 | - open files 40 | - current directory (or include '.') 41 | - path 42 | - include (list of strings) 43 | - exclude (list of strings) 44 | 45 | Maybe (not sure on these) 46 | - mark lines with matches (boolean) 47 | - querySelect style 48 | - find misspelled word 49 | - error (i.e. go to the next compile error or similar) 50 | - external call/script 51 | - highlight all matches (boolean) 52 | 53 | ## Might be a silly idea, but what about a set notation so say where and how to search 54 | 55 | Something that would describe what to search (e.g. search in comments or don't search in comments). 56 | 57 | within: code || comments || content || markup || quoted /* && marked && selection */ 58 | within: -code +comments -content &marked +markup "ed =selection 59 | 60 | 61 | ## Here is a draft of a multi-line find UI 62 | 63 | ``` 64 | find: dog 65 | replace: cat 66 | options: -exact +highlight +regex +smart -words +wrap 67 | within: +code +comments +content +markup +quotes 68 | that is: -marked -selected -changed 69 | paths: +example.txt 70 | exit^w forward^f reverse^r replace^s all^e mark^m 71 | ``` 72 | 73 | 74 | or 75 | 76 | 77 | 78 | ``` 79 | find: dog 80 | +regex -words -matchCase +multiLine # +marked 81 | replace: cat 82 | case(simple smart upper +lower) # +mark 83 | within: +code +comments +content +markup +quotes +license 84 | ~selected +changed # !marked 85 | paths: +example.txt 86 | # mark^m 87 | ``` 88 | 89 | 90 | 91 | 92 | 93 | ``` 94 | find: dog 95 | replace: cat 96 | [*]regex, [ ]words, [ ]matchCase, [ ]multiLine 97 | within: ( )code, ( )comments, ( )markup, ( )quotes, ( )license, ( )any; 98 | selected: ( )yes, ( )no, (*)any; 99 | changed: ( )yes, ( )no, (*)any; 100 | paths: +example.txt 101 | changeCase: (*)none, ( )smart, ( )upper, ( )lower; 102 | # mark^m 103 | ``` 104 | 105 | 106 | 107 | 108 | 109 | 110 | ``` 111 | find: dog 112 | replace: cat 113 | [*]regex [ ]words [ ]matchCase [ ]multiLine 114 | within: ( )code ( )comments ( )markup ( )quotes ( )license (*)any 115 | selected: ( )yes ( )no (*)any 116 | changed: ( )yes ( )no (*)any 117 | paths: +example.txt 118 | changeCase: (*)none ( )smart ( )upper ( )lower 119 | # mark^m 120 | ``` 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | ``` 129 | find: dog 130 | replace: cat 131 | [*]regex [ ]words [ ]matchCase [ ]multiLine 132 | changeCase: {none} 133 | within: {any} 134 | selected: {any} 135 | changed: {any} 136 | paths: +example.txt 137 | # mark^m 138 | ``` 139 | 140 | 141 | 142 | ## There are some options that I'd like to operate on the main document 143 | undo/redo/save/quit if these actions are done in the find UI, they should affect the current file. 144 | 145 | -------------------------------------------------------------------------------- /app/bookmark.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | 20 | class Bookmark(object): 21 | """ 22 | This bookmark object is used as a marker for different places in a 23 | text document. Note that because text buffer lines index at 0, all 24 | references to rows also assume that 0 is the first line. 25 | """ 26 | 27 | def __init__(self, beginRow, endRow, data): 28 | """ 29 | Creates a bookmark located at the specified rows. This will 30 | automatically cast the passed in rows into integers. 31 | Args: 32 | beginRow (int-like): The line that the bookmark starts on (inclusive). 33 | endRow (int-like): The line that the bookmark ends on (inclusive). 34 | data (other): This is used to store any information that you would 35 | like to to associate with this bookmark. It is an empty 36 | dictionary by default. 37 | """ 38 | self.__begin = int(beginRow) 39 | self.__end = int(endRow) 40 | self.data = data 41 | 42 | @property 43 | def range(self): 44 | return (self.begin, self.end) 45 | 46 | @range.setter 47 | def range(self, value): 48 | self.__begin, self.__end = sorted(int(x) for x in value) 49 | 50 | @property 51 | def begin(self): 52 | return self.__begin 53 | 54 | @begin.setter 55 | def begin(self, value): 56 | self.__begin, self.__end = sorted(int(x) for x in (value, self.__end)) 57 | 58 | @property 59 | def end(self): 60 | return self.__end 61 | 62 | @end.setter 63 | def end(self, value): 64 | self.__begin, self.__end = sorted(int(x) for x in (self.__begin, value)) 65 | 66 | def overlaps(self, bookmark): 67 | """ 68 | Takes in another bookmark object and returns True if this bookmark 69 | shares any rows with the passed in bookmark. 70 | """ 71 | begin1, end1 = self.range 72 | begin2, end2 = bookmark.range 73 | return begin1 <= end2 and end1 >= begin2 74 | 75 | def __contains__(self, row): 76 | """ 77 | Args: 78 | row (int): the row that you want to check. 79 | 80 | Returns: 81 | True if the passed in row is inside the bookmark's range. 82 | """ 83 | return self.begin <= row <= self.end 84 | 85 | def __lt__(self, other): 86 | assert isinstance(other, Bookmark) 87 | return self.range < other.range 88 | 89 | def __gt__(self, other): 90 | assert isinstance(other, Bookmark) 91 | return self.range > other.range 92 | 93 | def __eq__(self, other): 94 | assert isinstance(other, Bookmark) 95 | return self.range == other.range 96 | 97 | def __ne__(self, other): 98 | assert isinstance(other, Bookmark) 99 | return self.range != other.range 100 | 101 | def __le__(self, other): 102 | assert isinstance(other, Bookmark) 103 | return self.range <= other.range 104 | 105 | def __ge__(self, other): 106 | assert isinstance(other, Bookmark) 107 | return self.range >= other.range 108 | 109 | def __hash__(self): 110 | # NOTE: Any two bookmarks with the same range WILL have the same hash 111 | # value. self.range can also change, so be careful when using this in a 112 | # hash table. 113 | return hash(self.range) 114 | 115 | def __repr__(self): 116 | return repr(self.range) 117 | -------------------------------------------------------------------------------- /help.md: -------------------------------------------------------------------------------- 1 | # Help for ci_edit 2 | 3 | ### Contents: 4 | Quick Tips 5 | Key Bindings 6 | Execute Prompt 7 | Prediction Prompt 8 | Note 9 | 10 | 11 | ## Quick Tips (How to quit or exit) 12 | 13 | To exit the program: hold the control key and press q. 14 | A shorthand for "hold the control key and press q" is ctrl+q, which can also be 15 | written ^q (the chevron represents 'control'). 16 | 17 | 18 | ## Key Bindings 19 | 20 | ### Within the main text window: 21 | ``` 22 | ctrl+a Select all 23 | ctrl+c Copy 24 | ctrl+e Execute prompt (e:) 25 | ctrl+f Find prompt (find:) 26 | ctrl+g Go to line prompt (goto:) 27 | ctrl+l Select current line (subsequent select next line) 28 | ctrl+o Open file prompt (open:) 29 | ctrl+p Prediction prompt (p:) 30 | ctrl+q Quit (exit editor) 31 | ctrl+r Reverse find 32 | ctrl+s Save file 33 | ctrl+v Paste 34 | ctrl+w Close document 35 | ctrl+x Cut 36 | ctrl+y Redo 37 | ctrl+z Undo 38 | ``` 39 | ### Within Any Prompt 40 | 41 | Prompts in this context are the e:, find:, goto:, and p: modes. 42 | 43 | Text commands (such as cut and paste) 44 | operate on the prompt text rather 45 | than the main window. 46 | ``` 47 | return Perform action and return to editing the file 48 | esc Abort action and return to editing the file 49 | ctrl+a Select all* 50 | ctrl+c Copy* 51 | ctrl+l Select whole line* 52 | ctrl+q Quit (exit editor) 53 | ctrl+s Save file 54 | ctrl+v Paste* 55 | ctrl+x Cut* 56 | ctrl+y Redo* 57 | ctrl+z Undo* 58 | ``` 59 | * Affects find: prompt, not the document. 60 | 61 | ### Within the Find prompt: 62 | 63 | See "Within Any Prompt", plus these: 64 | ``` 65 | ctrl+f Find next 66 | ctrl+g Find next 67 | ctrl+o Switch to Open prompt (open:) 68 | ctrl+p Switch to Prediction prompt (p:) 69 | ctrl+q Quit (exit editor) 70 | ctrl+r Reverse find 71 | ``` 72 | ### Within the Goto line prompt: 73 | 74 | See "Within Any Prompt", plus these: 75 | ``` 76 | b Jump to bottom of document 77 | h Jump to half-way in the document 78 | t Jump to top of document 79 | ctrl+p Prediction prompt (p:) 80 | ``` 81 | * Affects goto: prompt, not the document. 82 | 83 | ### Execute Prompt 84 | 85 | The execution prompt allows you to run powerful commands to manipulate the 86 | currently selected text or perform other actions. 87 | ``` 88 | sort Sort selected text 89 | | Pipe selected text to and replace selection with result. 90 | Example: 91 | 1. Select several lines of text 92 | 2. Press ctrl+e 93 | 3. At the e: prompt type: |sort -u 94 | 4. Press return 95 | Result: the lines will be sorted and duplicate lines will be 96 | removed (-u stands for 'unique'). 97 | ! Execute in a sub-shell 98 | ``` 99 | ### Prediction Prompt 100 | 101 | The prediction prompt tries to guess where you'd like to visit next. The upper 102 | window will show a list of files or locations that are somehow related to the 103 | current file. E.g. if the current file is a c++ file, it may suggest the 104 | header file as a someplace you'd like to visit. 105 | ``` 106 | ctrl+p Move selection up one line 107 | ctrl+n Move selection down one line 108 | return Open (or switch to) that file 109 | ``` 110 | 111 | ## Note 112 | 113 | This is not an official Google product. 114 | 115 | 116 | 117 | Copyright 2016 Google Inc. 118 | 119 | Licensed under the Apache License, Version 2.0 (the "License"); 120 | you may not use this file except in compliance with the License. 121 | You may obtain a copy of the License at 122 | 123 | http://www.apache.org/licenses/LICENSE-2.0 124 | 125 | Unless required by applicable law or agreed to in writing, software 126 | distributed under the License is distributed on an "AS IS" BASIS, 127 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128 | See the License for the specific language governing permissions and 129 | limitations under the License. 130 | -------------------------------------------------------------------------------- /app/help.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | import os 20 | import sys 21 | 22 | dirPath = os.path.split(os.path.abspath(os.path.dirname(__file__)))[0] 23 | 24 | docs = { 25 | "command line": """\ 26 | Command line help 27 | %s [args] [file...] 28 | 29 | - Read from standard in. 30 | -- Treat remaining arguments as file names. 31 | --clearHistory Cleanup the file (and undo) into in ~/.ci_edit/. 32 | --log Display logging and debug info. 33 | --help Print this help message then exit. 34 | --keys Print key bindings then exit. 35 | --singleThread Do not use a background thread for parsing. 36 | --test Run unit tests and exit. 37 | --version Print version and license information then exit.\ 38 | """ 39 | % (sys.argv[0],), 40 | "key bindings": """\ 41 | Key Bindings 42 | 43 | Within the main text window: 44 | 45 | ctrl+a Select all 46 | ctrl+c Copy 47 | ctrl+e Execute prompt (e:) 48 | ctrl+f Find prompt (find:) 49 | ctrl+g Go to line prompt (goto:) 50 | ctrl+l Select current line (subsequent select next line) 51 | ctrl+o Open file prompt (open:) 52 | ctrl+p Prediction prompt (p:) 53 | ctrl+q Quit (exit editor) 54 | ctrl+r Reverse find 55 | ctrl+s Save file 56 | ctrl+v Paste 57 | ctrl+w Close document 58 | ctrl+x Cut 59 | ctrl+y Redo 60 | ctrl+z Undo 61 | 62 | Within the Find prompt: 63 | 64 | Text commands (such as cut and paste) 65 | operate on the prompt text rather 66 | than the main window. 67 | 68 | return Exit Find 69 | esc Exit Find 70 | ctrl+a Select all* 71 | ctrl+c Copy* 72 | ctrl+f Find next 73 | ctrl+g Find next 74 | ctrl+l Select whole line* 75 | ctrl+o Switch to Open prompt (open:) 76 | ctrl+p Switch to Prediction prompt (p:) 77 | ctrl+q Quit (exit editor) 78 | ctrl+r Reverse find 79 | ctrl+s Save file 80 | ctrl+v Paste* 81 | ctrl+x Cut* 82 | ctrl+y Redo* 83 | ctrl+z Undo* 84 | 85 | * Affects find: prompt, not the document. 86 | 87 | Within the Goto line prompt: 88 | 89 | Text commands (such as cut and paste) 90 | operate on the prompt text rather 91 | than the main window. 92 | 93 | b Jump to bottom of document 94 | h Jump to half-way in the document 95 | t Jump to top of document 96 | return Exit Goto 97 | esc Exit Goto 98 | ctrl+a Select all* 99 | ctrl+c Copy* 100 | ctrl+l Select whole line* 101 | ctrl+p Prediction prompt (p:) 102 | ctrl+q Quit (exit editor) 103 | ctrl+s Save file 104 | ctrl+v Paste* 105 | ctrl+x Cut* 106 | ctrl+y Redo* 107 | ctrl+z Undo* 108 | 109 | * Affects goto: prompt, not the document.\ 110 | """, 111 | "tips": [ 112 | """Welcome to ci_edit.""", 113 | "", 114 | """Tips: press ctrl+q to quit, ctrl+s (aka ^s) to save, """ 115 | """^a select all,""", 116 | """ ^z cut, ^x cut, ^c copy, ^v paste, ^f find, """ 117 | """^o open file, ^w close,""", 118 | """ ^g goto line. ^e and ^p are need more explanation, """ 119 | """see help.md file.""", 120 | "", 121 | # """What do you think of the help text above?""", 122 | # """Please add feedback""" 123 | # """ to https://github.com/google/ci_edit/issues/107""", 124 | ], 125 | "version": """\ 126 | Version (build iteration): v51 127 | Within Python %s 128 | See LICENSE for license information 129 | See readme.md for an introduction 130 | Both files may be found in "%s" 131 | Please give the gift of feedback and bug reports at 132 | https://github.com/google/ci_edit/issues\ 133 | """ 134 | % ( 135 | sys.version, 136 | dirPath, 137 | ), 138 | "welcome": """\ 139 | Welcome to the ci_edit text editor.\ 140 | """, 141 | } 142 | -------------------------------------------------------------------------------- /third_party/pyperclip/clipboards.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import subprocess 4 | from .exceptions import PyperclipException 5 | 6 | EXCEPT_MSG = """ 7 | Pyperclip could not find a copy/paste mechanism for your system. 8 | For more information, please visit https://pyperclip.readthedocs.org """ 9 | PY2 = sys.version_info[0] == 2 10 | text_type = unicode if PY2 else str 11 | 12 | 13 | def init_osx_clipboard(): 14 | def copy_osx(text): 15 | p = subprocess.Popen(["pbcopy", "w"], stdin=subprocess.PIPE, close_fds=True) 16 | p.communicate(input=text.encode("utf-8")) 17 | 18 | def paste_osx(): 19 | p = subprocess.Popen(["pbpaste", "r"], stdout=subprocess.PIPE, close_fds=True) 20 | stdout, stderr = p.communicate() 21 | return stdout.decode("utf-8") 22 | 23 | return copy_osx, paste_osx 24 | 25 | 26 | def init_gtk_clipboard(): 27 | import gtk 28 | 29 | def copy_gtk(text): 30 | global cb 31 | cb = gtk.Clipboard() 32 | cb.set_text(text) 33 | cb.store() 34 | 35 | def paste_gtk(): 36 | clipboardContents = gtk.Clipboard().wait_for_text() 37 | # for python 2, returns None if the clipboard is blank. 38 | if clipboardContents is None: 39 | return "" 40 | else: 41 | return clipboardContents 42 | 43 | return copy_gtk, paste_gtk 44 | 45 | 46 | def init_qt_clipboard(): 47 | # $DISPLAY should exist 48 | from PyQt4.QtGui import QApplication 49 | 50 | app = QApplication([]) 51 | 52 | def copy_qt(text): 53 | cb = app.clipboard() 54 | cb.setText(text) 55 | 56 | def paste_qt(): 57 | cb = app.clipboard() 58 | return text_type(cb.text()) 59 | 60 | return copy_qt, paste_qt 61 | 62 | 63 | def init_xclip_clipboard(): 64 | def copy_xclip(text): 65 | p = subprocess.Popen( 66 | ["xclip", "-selection", "c"], stdin=subprocess.PIPE, close_fds=True 67 | ) 68 | p.communicate(input=text.encode("utf-8")) 69 | 70 | def paste_xclip(): 71 | with open(os.devnull, "w") as devnull: 72 | p = subprocess.Popen( 73 | ["xclip", "-selection", "c", "-o"], 74 | stdout=subprocess.PIPE, 75 | stderr=devnull, 76 | close_fds=True, 77 | ) 78 | stdout, stderr = p.communicate() 79 | return stdout.decode("utf-8") 80 | 81 | return copy_xclip, paste_xclip 82 | 83 | 84 | def init_xsel_clipboard(): 85 | def copy_xsel(text): 86 | p = subprocess.Popen( 87 | ["xsel", "-b", "-i"], stdin=subprocess.PIPE, close_fds=True 88 | ) 89 | p.communicate(input=text.encode("utf-8")) 90 | 91 | def paste_xsel(): 92 | p = subprocess.Popen( 93 | ["xsel", "-b", "-o"], stdout=subprocess.PIPE, close_fds=True 94 | ) 95 | stdout, stderr = p.communicate() 96 | return stdout.decode("utf-8") 97 | 98 | return copy_xsel, paste_xsel 99 | 100 | 101 | def init_klipper_clipboard(): 102 | def copy_klipper(text): 103 | p = subprocess.Popen( 104 | [ 105 | "qdbus", 106 | "org.kde.klipper", 107 | "/klipper", 108 | "setClipboardContents", 109 | text.encode("utf-8"), 110 | ], 111 | stdin=subprocess.PIPE, 112 | close_fds=True, 113 | ) 114 | p.communicate(input=None) 115 | 116 | def paste_klipper(): 117 | p = subprocess.Popen( 118 | ["qdbus", "org.kde.klipper", "/klipper", "getClipboardContents"], 119 | stdout=subprocess.PIPE, 120 | close_fds=True, 121 | ) 122 | stdout, stderr = p.communicate() 123 | 124 | # Workaround for https://bugs.kde.org/show_bug.cgi?id=342874 125 | # TODO: https://github.com/asweigart/pyperclip/issues/43 126 | clipboardContents = stdout.decode("utf-8") 127 | # even if blank, Klipper will append a newline at the end 128 | assert len(clipboardContents) > 0 129 | # make sure that newline is there 130 | assert clipboardContents.endswith("\n") 131 | if clipboardContents.endswith("\n"): 132 | clipboardContents = clipboardContents[:-1] 133 | return clipboardContents 134 | 135 | return copy_klipper, paste_klipper 136 | 137 | 138 | def init_no_clipboard(): 139 | class ClipboardUnavailable(object): 140 | def __call__(self, *args, **kwargs): 141 | raise PyperclipException(EXCEPT_MSG) 142 | 143 | if PY2: 144 | 145 | def __nonzero__(self): 146 | return False 147 | 148 | else: 149 | 150 | def __bool__(self): 151 | return False 152 | 153 | return ClipboardUnavailable(), ClipboardUnavailable() 154 | -------------------------------------------------------------------------------- /app/unit_test_buffer_file.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | try: 20 | unicode 21 | except NameError: 22 | unicode = str 23 | unichr = chr 24 | 25 | import os 26 | import unittest 27 | 28 | try: 29 | import unittest.mock 30 | except ImportError: 31 | print("\nWarning: import unittest.mock failed. Some tests will be skipped.") 32 | pass 33 | 34 | import app.buffer_file as test_buffer_file 35 | 36 | 37 | class pathRowColumnTestCases(unittest.TestCase): 38 | def setUp(self): 39 | pass 40 | 41 | def tearDown(self): 42 | pass 43 | 44 | def test_path_row_column(self): 45 | if not hasattr(unittest, "mock"): 46 | return 47 | # Shortcuts. 48 | originalIsFile = test_buffer_file.os.path.isfile 49 | decode = test_buffer_file.path_row_column 50 | Mock = unittest.mock.MagicMock 51 | 52 | mock = Mock(side_effect=[False, True]) 53 | self.assertEqual(False, mock("a")) 54 | self.assertEqual(True, mock("a")) 55 | with self.assertRaises(StopIteration): 56 | self.assertEqual(True, mock("a")) 57 | 58 | os.path.isfile = Mock(side_effect=[False, True]) 59 | self.assertEqual(False, os.path.isfile("a")) 60 | self.assertEqual(True, os.path.isfile("a")) 61 | with self.assertRaises(StopIteration): 62 | self.assertEqual(True, os.path.isfile("a")) 63 | 64 | os.path.isfile = Mock(side_effect=[False, True]) 65 | self.assertEqual(decode(u"", u""), (u"", None, None)) 66 | self.assertEqual(decode(u"/", u""), (u"/", None, None)) 67 | 68 | os.path.isfile = Mock(side_effect=[False, False]) 69 | self.assertEqual(decode(u"//apple", u"/stuff"), (u"/stuff/apple", None, None)) 70 | 71 | os.path.isfile = Mock(side_effect=[False, False]) 72 | self.assertEqual(decode(u"//apple", None), (u"//apple", None, None)) 73 | 74 | os.path.isfile = Mock(side_effect=[False, False, False]) 75 | self.assertEqual(decode(u":5", u""), (u"", 4, None)) 76 | 77 | os.path.isfile = Mock(side_effect=[False, False, False]) 78 | self.assertEqual(decode(u"/:5", u""), (u"/", 4, None)) 79 | 80 | os.path.isfile = Mock(side_effect=[False, False, False]) 81 | self.assertEqual(decode(u"//apple:5", u"/stuff"), (u"/stuff/apple", 4, None)) 82 | 83 | os.path.isfile = Mock(side_effect=[False, False, False]) 84 | self.assertEqual(decode(u"//apple:5", None), (u"//apple", 4, None)) 85 | 86 | os.path.isfile = Mock(side_effect=[False, True]) 87 | self.assertEqual(decode(u"//apple", u"/stuff"), (u"/stuff/apple", None, None)) 88 | 89 | os.path.isfile = Mock(side_effect=[False, True]) 90 | self.assertEqual(decode(u"//apple", None), (u"apple", None, None)) 91 | 92 | os.path.isfile = Mock(side_effect=[False, True]) 93 | self.assertEqual(decode(u":5", u""), (u"", 4, None)) 94 | 95 | os.path.isfile = Mock(side_effect=[False, True]) 96 | self.assertEqual(decode(u"/:5", u""), (u"/", 4, None)) 97 | 98 | os.path.isfile = Mock(side_effect=[False, True]) 99 | self.assertEqual(decode(u"//apple:5", u"/stuff"), (u"/stuff/apple", 4, None)) 100 | 101 | os.path.isfile = Mock(side_effect=[False, True, True]) 102 | self.assertEqual(decode(u"//apple:5", None), (u"apple", 4, None)) 103 | 104 | os.path.isfile = Mock(side_effect=[False, True, True]) 105 | self.assertEqual(decode(u"//apple:5:", None), (u"apple", 4, None)) 106 | 107 | os.path.isfile = Mock(side_effect=[False, True, True]) 108 | self.assertEqual(decode(u"//apple:5:9", None), (u"apple", 4, 8)) 109 | 110 | os.path.isfile = Mock(side_effect=[False, True, True]) 111 | self.assertEqual(decode(u"//apple:5:9:", None), (u"apple", 4, 8)) 112 | 113 | os.path.isfile = Mock(side_effect=[False, True, True]) 114 | self.assertEqual(decode(u"apple:banana", None), (u"apple:banana", None, None)) 115 | 116 | os.path.isfile = Mock(side_effect=[False, True, True]) 117 | self.assertEqual( 118 | decode(u"//apple:banana:cat:", None), (u"apple:banana:cat:", None, None) 119 | ) 120 | 121 | os.path.isfile = originalIsFile 122 | -------------------------------------------------------------------------------- /app/unit_test_undo_redo.py: -------------------------------------------------------------------------------- 1 | # -*- coding: latin-1 -*- 2 | 3 | # Copyright 2017 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from __future__ import absolute_import 18 | from __future__ import division 19 | from __future__ import print_function 20 | 21 | import curses 22 | import os 23 | import sys 24 | 25 | from app.curses_util import * 26 | import app.ci_program 27 | import app.fake_curses_testing 28 | 29 | kTestFile = u"#undo_redo_test_file_with_unlikely_file_name~" 30 | 31 | 32 | class UndoRedoTestCases(app.fake_curses_testing.FakeCursesTestCase): 33 | def setUp(self): 34 | self.longMessage = True 35 | if os.path.isfile(kTestFile): 36 | os.unlink(kTestFile) 37 | self.assertFalse(os.path.isfile(kTestFile)) 38 | app.fake_curses_testing.FakeCursesTestCase.set_up(self) 39 | 40 | def test_undo_bracketed_paste(self): 41 | # self.set_movie_mode(True) 42 | self.run_with_test_file( 43 | kTestFile, 44 | [ 45 | self.display_check(2, 7, [u" "]), 46 | curses.ascii.ESC, 47 | app.curses_util.BRACKETED_PASTE_BEGIN, 48 | u"a", 49 | u"b", 50 | u"c", 51 | curses.ascii.ESC, 52 | app.curses_util.BRACKETED_PASTE_END, 53 | self.display_check(2, 7, [u"abc "]), 54 | CTRL_Z, 55 | self.display_check(2, 7, [u" "]), 56 | CTRL_Q, 57 | ], 58 | ) 59 | 60 | def test_basic_undo(self): 61 | # self.set_movie_mode(True) 62 | self.run_with_test_file( 63 | kTestFile, 64 | [ 65 | self.display_check(2, 7, [u" "]), 66 | self.write_text(u"sand"), 67 | self.display_check(2, 7, [u"sand "]), 68 | KEY_BACKSPACE1, 69 | u"s", 70 | self.display_check(2, 7, [u"sans "]), 71 | CTRL_Z, 72 | self.display_check(2, 7, [u"san "]), 73 | CTRL_Z, 74 | self.display_check(2, 7, [u"sand "]), 75 | CTRL_Z, 76 | self.display_check(2, 7, [u" "]), 77 | # Don't go past first change. 78 | CTRL_Z, 79 | self.display_check(2, 7, [u" "]), 80 | CTRL_Y, 81 | self.display_check(2, 7, [u"sand "]), 82 | CTRL_Y, 83 | self.display_check(2, 7, [u"san "]), 84 | CTRL_Y, 85 | self.display_check(2, 7, [u"sans "]), 86 | # Don't go past last change. 87 | CTRL_Y, 88 | self.display_check(2, 7, [u"sans "]), 89 | CTRL_Z, 90 | self.display_check(2, 7, [u"san "]), 91 | CTRL_Z, 92 | self.display_check(2, 7, [u"sand "]), 93 | CTRL_Z, 94 | self.display_check(2, 7, [u" "]), 95 | CTRL_Q, 96 | ], 97 | ) 98 | 99 | def test_undo_words(self): 100 | # self.set_movie_mode(True) 101 | self.run_with_test_file( 102 | kTestFile, 103 | [ 104 | self.display_check(2, 7, [u" "]), 105 | self.write_text(u"one two "), 106 | self.display_check(2, 7, [u"one two "]), 107 | self.write_text(u"three four "), 108 | self.display_check(2, 7, [u"one two three four", " "]), 109 | KEY_SHIFT_LEFT, 110 | KEY_SHIFT_LEFT, 111 | KEY_SHIFT_LEFT, 112 | KEY_SHIFT_LEFT, 113 | KEY_SHIFT_LEFT, 114 | KEY_SHIFT_LEFT, 115 | KEY_SHIFT_LEFT, 116 | KEY_SHIFT_LEFT, 117 | KEY_SHIFT_LEFT, 118 | KEY_SHIFT_LEFT, 119 | KEY_SHIFT_LEFT, 120 | KEY_SHIFT_LEFT, 121 | KEY_SHIFT_LEFT, 122 | KEY_SHIFT_LEFT, 123 | KEY_SHIFT_LEFT, 124 | self.write_text(u"five "), 125 | self.display_check(2, 7, [u"one five"]), 126 | CTRL_Z, 127 | self.display_check(2, 7, [u"one two three four "]), 128 | CTRL_Z, 129 | self.display_check(2, 7, [u"one two "]), 130 | CTRL_Y, 131 | self.display_check(2, 7, [u"one two three four "]), 132 | CTRL_Y, 133 | self.display_check(2, 7, [u"one five "]), 134 | CTRL_Q, 135 | u"n", 136 | ], 137 | ) 138 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2017 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | # Install File Description: 18 | # 19 | # This is an init (install) script that first copies or updates the editor 20 | # code to the path: /opt/[$PWD], which will be your installation. 21 | # Then, a symbolic link (sym-link) is created in the directory /usr/local/bin. 22 | # This directory is generally designated for user programs not managed 23 | # by the distribution package manager. 24 | # The link references the execution command in the install directory. 25 | # The default command will be `we`, but this can be customized to user 26 | # preference during the install. 27 | 28 | if [ "$(id -u)" != "0" ]; then 29 | echo "Usage: sudo ./install.sh (please use root privileges)" 30 | [[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1 31 | fi 32 | 33 | # Source path to find current directory and to copy application to /opt/. 34 | SRC_PATH=$(dirname "$0") # Path from which install was executed. 35 | SRC_PATH=$(cd "$SRC_PATH" && pwd) # absolute path 36 | if [ -z "$SRC_PATH" ]; then 37 | # Exit if for some reason, the path is empty string. 38 | [[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1 39 | fi 40 | 41 | # Grab current directory name to use as subdirectory for the installed app. 42 | APP_DIR=$(basename "$SRC_PATH") 43 | # Path for sym link to executable ci.py. 44 | BIN_PATH="/usr/local/bin" 45 | # Location of install directory. 46 | APP_PATH="/opt" 47 | # Full install directory. 48 | INSTALL_DIR="${APP_PATH}/${APP_DIR}" 49 | 50 | echo "* *********************************************************** *" 51 | echo "* *" 52 | echo "* installation steps: *" 53 | echo "* *" 54 | echo "* (1) copies (or updates) '$APP_DIR' directory to the path: *" 55 | echo "* '$INSTALL_DIR' *" 56 | echo "* NOTE: update will use the command: *" 57 | echo "* $ rm -rf $INSTALL_DIR *" 58 | echo "* *" 59 | echo "* (2) creates (or updates) the execution command: *" 60 | echo "* (a) this will be a sym link to the install directory *" 61 | echo "* executable 'ci.py' copied to the path: *" 62 | echo "* '/usr/local/bin' --> generally designated for *" 63 | echo "* user programs. *" 64 | echo "* (b) The command will be given the default: *" 65 | echo "* command name of: 'we' *" 66 | echo "* (c) If you would like to specify the command name, *" 67 | echo "* you will be prompted for an input name. *" 68 | echo "* NOTE: Be sure to specify a UNIQUE name *" 69 | echo "* *" 70 | echo "* *********************************************************** *" 71 | echo "" 72 | echo "Type 'y' or 'Y' to continue, or anything else to quit" 73 | read -p "Continue ? " -n 1 -r INSTALL_REPLY 74 | echo "" 75 | if [[ ! "$INSTALL_REPLY" =~ ^[Yy]$ ]]; then 76 | echo "...Goodbye" 77 | [[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1 78 | else 79 | echo "To customize the ci_edit command for your CLI, please type:" 80 | echo "'y' or 'Y', or anything else to use the default command 'we'" 81 | read -p "Customize Command ? " -n 1 -r CMD_REPLY 82 | echo "" 83 | if [[ "$CMD_REPLY" =~ ^[Yy]$ ]]; then 84 | read -p "Your Custom Unique command: " -r THE_CMD 85 | else 86 | THE_CMD="we" 87 | fi 88 | echo "...installing" 89 | sleep 1 90 | fi 91 | 92 | # Go over board to avoid "rm -rf /"; e.g. APP_PATH is set above, testing anyway. 93 | if [[ -z "$APP_PATH" || -z "${APP_DIR}" || "$INSTALL_DIR" == "/" ]]; then 94 | echo "Something is incorrect about the install directory. Exiting." 95 | exit -1 96 | fi 97 | # Yes, this is redundant with the above. User safety is top priority. 98 | # Only continues to delete if directory exists and is not root '/' 99 | if [[ -n "$APP_PATH" && -n "${APP_DIR}" && "$INSTALL_DIR" != "/" ]]; then 100 | rm -rf "$INSTALL_DIR" 101 | fi 102 | 103 | # Create the directory if not already existing /opt/. 104 | mkdir -p /opt/ 105 | # Copies Source to /opt/$INSTALL_DIR. 106 | cp -Rv "$SRC_PATH" "$INSTALL_DIR" 107 | # Make installed directories usable by all users. 108 | find "$INSTALL_DIR" -type d -exec chmod +rx {} \; 109 | # Make installed files readable by all users. 110 | chmod -R +r "$INSTALL_DIR" 111 | # Allow all users to execute the editor. 112 | chmod +rx "$INSTALL_DIR/ci.py" 113 | ln -sf "${APP_PATH}/${APP_DIR}/ci.py" "${BIN_PATH}/${THE_CMD}" 114 | echo "...Success! Enjoy." 115 | -------------------------------------------------------------------------------- /app/sm_editor.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """Key bindings for the slash-menu editor.""" 15 | 16 | from __future__ import absolute_import 17 | from __future__ import division 18 | from __future__ import print_function 19 | 20 | import curses 21 | import curses.ascii 22 | import app.editor 23 | import os 24 | import re 25 | import text_buffer 26 | 27 | from app.curses_util import * 28 | import app.controller 29 | 30 | 31 | class CiEdit(app.controller.Controller): 32 | """Keyboard mappings for ci.""" 33 | 34 | def __init__(self, prg, textBuffer): 35 | app.controller.Controller.__init__(self, prg, None, "CiEdit") 36 | self.prg.log("CiEdit.__init__") 37 | self.textBuffer = textBuffer 38 | self.commandSet_Main = { 39 | CTRL_SPACE: self.switch_to_command_set_cmd, 40 | CTRL_A: textBuffer.cursor_start_of_line, 41 | CTRL_B: textBuffer.cursor_left, 42 | KEY_LEFT: self.cursor_left, 43 | CTRL_C: self.edit_copy, 44 | CTRL_H: self.backspace, 45 | KEY_BACKSPACE1: textBuffer.backspace, 46 | KEY_BACKSPACE2: textBuffer.backspace, 47 | KEY_BACKSPACE3: textBuffer.backspace, 48 | CTRL_D: self.delete, 49 | CTRL_E: self.cursor_end_of_line, 50 | CTRL_F: self.cursor_right, 51 | KEY_RIGHT: self.cursor_right, 52 | CTRL_J: self.carriage_return, 53 | CTRL_K: self.delete_to_end_of_line, 54 | CTRL_L: self.win.refresh, 55 | CTRL_N: self.cursor_down, 56 | KEY_DOWN: self.cursor_down, 57 | CTRL_O: self.split_line, 58 | CTRL_P: self.cursor_up, 59 | KEY_UP: self.cursor_up, 60 | CTRL_V: self.edit_paste, 61 | CTRL_X: self.edit_cut, 62 | CTRL_Y: self.redo, 63 | CTRL_Z: self.undo, 64 | CTRL_BACKSLASH: self.changeToCmdMode, 65 | # ord('/'): self.switch_to_command_set_cmd, 66 | } 67 | 68 | self.commandSet_Cmd = { 69 | ord("a"): self.switch_to_command_set_application, 70 | ord("f"): self.switch_to_command_set_file, 71 | ord("s"): self.switch_to_command_set_select, 72 | ord(";"): self.switch_to_command_set_main, 73 | ord("'"): self.marker_place, 74 | } 75 | 76 | self.commandSet_Application = { 77 | ord("q"): self.prg.quit, 78 | ord("t"): self.test, 79 | ord("w"): self.file_write, 80 | ord(";"): self.switch_to_command_set_main, 81 | } 82 | 83 | self.commandSet_File = { 84 | ord("o"): self.switch_to_command_set_file_open, 85 | ord("w"): self.file_write, 86 | ord(";"): self.switch_to_command_set_main, 87 | } 88 | 89 | self.commandSet_FileOpen = { 90 | ord(";"): self.switch_to_command_set_main, 91 | } 92 | 93 | self.commandSet_Select = { 94 | ord("a"): self.selection_all, 95 | ord("b"): self.selection_block, 96 | ord("c"): self.selection_character, 97 | ord("l"): self.selection_line, 98 | ord("x"): self.selection_none, 99 | ord(";"): self.switch_to_command_set_main, 100 | } 101 | 102 | self.commandDefault = self.insert_printable 103 | self.commandSet = self.commandSet_Main 104 | 105 | def switch_to_command_set_main(self, ignored=1): 106 | self.log("ci main", repr(self.prg)) 107 | self.commandDefault = self.insert_printable 108 | self.commandSet = self.commandSet_Main 109 | 110 | def switch_to_command_set_cmd(self): 111 | self.log("ci cmd") 112 | self.commandDefault = self.textBuffer.no_op 113 | self.commandSet = self.commandSet_Cmd 114 | 115 | def switch_to_command_set_application(self): 116 | self.log("ci application") 117 | self.commandDefault = self.textBuffer.no_op 118 | self.commandSet = self.commandSet_Application 119 | 120 | def switch_to_command_set_file(self): 121 | self.commandDefault = self.textBuffer.no_op 122 | self.commandSet = self.commandSet_File 123 | 124 | def switch_to_command_set_file_open(self): 125 | self.log("switch_to_command_set_file_open") 126 | self.commandDefault = self.pathInsertPrintable 127 | self.commandSet = self.commandSet_FileOpen 128 | 129 | def switch_to_main_and_do_command(self, ch): 130 | self.log("switch_to_main_and_do_command") 131 | self.switch_to_command_set_main() 132 | self.do_command(ch) 133 | 134 | def switch_to_command_set_select(self): 135 | self.log("ci select") 136 | self.commandDefault = self.SwitchToMainAndDoCommand 137 | self.commandSet = self.commandSet_Select 138 | self.selection_character() 139 | -------------------------------------------------------------------------------- /app/debug_window.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | try: 20 | unicode 21 | except NameError: 22 | unicode = str 23 | unichr = chr 24 | 25 | import curses 26 | 27 | import app.curses_util 28 | import app.log 29 | import app.window 30 | 31 | 32 | class DebugWindow(app.window.ActiveWindow): 33 | def __init__(self, program, host): 34 | app.window.ActiveWindow.__init__(self, program, host) 35 | 36 | def debug_draw(self, program, win): 37 | """Draw real-time debug information to the screen.""" 38 | textBuffer = win.textBuffer 39 | self.writeLineRow = 0 40 | intent = u"noIntent" 41 | if hasattr(win, u"userIntent"): 42 | intent = win.userIntent 43 | color = program.color.get(u"debug_window") 44 | self.write_line( 45 | u" cRow %3d cCol %2d goalCol %2d %s" 46 | % ( 47 | win.textBuffer.penRow, 48 | win.textBuffer.penCol, 49 | win.textBuffer.goalCol, 50 | intent, 51 | ), 52 | color, 53 | ) 54 | self.write_line( 55 | u" pRow %3d pCol %2d chRow %4d" 56 | % (textBuffer.penRow, textBuffer.penCol, textBuffer.debugUpperChangedRow), 57 | color, 58 | ) 59 | self.write_line( 60 | u" mkrRow %3d mkrCol %2d sm %d" 61 | % (textBuffer.markerRow, textBuffer.markerCol, textBuffer.selectionMode), 62 | color, 63 | ) 64 | self.write_line( 65 | u"scrlRow %3d scrlCol %2d lines %3d" 66 | % (win.scrollRow, win.scrollCol, textBuffer.parser.row_count()), 67 | color, 68 | ) 69 | y, x = win.top, win.left 70 | maxRow, maxCol = win.rows, win.cols 71 | self.write_line( 72 | u"y %2d x %2d maxRow %d maxCol %d baud %d color %d" 73 | % (y, x, maxRow, maxCol, curses.baudrate(), curses.can_change_color()), 74 | color, 75 | ) 76 | screenRows, screenCols = program.cursesScreen.getmaxyx() 77 | self.write_line( 78 | u"scr rows %d cols %d mlt %f/%f pt %f" 79 | % ( 80 | screenRows, 81 | screenCols, 82 | program.mainLoopTime, 83 | program.mainLoopTimePeak, 84 | textBuffer.parserTime, 85 | ), 86 | color, 87 | ) 88 | self.write_line( 89 | u"ch %3s %s" 90 | % (program.ch, app.curses_util.curses_key_name(program.ch) or u"UNKNOWN"), 91 | color, 92 | ) 93 | self.write_line(u"win %r" % (win,), color) 94 | self.write_line(u"foc %r" % (program.programWindow.focusedWindow,), color) 95 | self.write_line(u"tb %r" % (textBuffer,), color) 96 | (id, mouseCol, mouseRow, mouseZ, bState) = program.debugMouseEvent 97 | self.write_line( 98 | u"mouse id %d, mouseCol %d, mouseRow %d, mouseZ %d" 99 | % (id, mouseCol, mouseRow, mouseZ), 100 | color, 101 | ) 102 | self.write_line( 103 | u"bState %s %d" % (app.curses_util.mouse_button_name(bState), bState), color 104 | ) 105 | self.write_line(u"start_and_end %r" % (textBuffer.start_and_end(),), color) 106 | 107 | 108 | class DebugUndoWindow(app.window.ActiveWindow): 109 | def __init__(self, program, host): 110 | app.window.ActiveWindow.__init__(self, program, host) 111 | 112 | def debug_undo_draw(self, win): 113 | """Draw real-time debug information to the screen.""" 114 | textBuffer = win.textBuffer 115 | self.writeLineRow = 0 116 | # Display some of the redo chain. 117 | colorPrefs = win.program.color 118 | redoColorA = colorPrefs.get(100) 119 | self.write_line( 120 | u"procTemp %d temp %r" 121 | % ( 122 | textBuffer.processTempChange, 123 | textBuffer.tempChange, 124 | ), 125 | redoColorA, 126 | ) 127 | self.write_line( 128 | u"redoIndex %3d savedAt %3d depth %3d" 129 | % ( 130 | textBuffer.redoIndex, 131 | textBuffer.savedAtRedoIndex, 132 | len(textBuffer.redo_chain), 133 | ), 134 | redoColorA, 135 | ) 136 | redoColorB = colorPrefs.get(101) 137 | split = 8 138 | for i in range(textBuffer.redoIndex - split, textBuffer.redoIndex): 139 | text = i >= 0 and repr(textBuffer.redo_chain[i]) or u"" 140 | self.write_line(unicode(text), redoColorB) 141 | redoColorC = colorPrefs.get(1) 142 | for i in range(textBuffer.redoIndex, textBuffer.redoIndex + split - 1): 143 | text = i < len(textBuffer.redo_chain) and textBuffer.redo_chain[i] or "" 144 | self.write_line(unicode(text), redoColorC) 145 | -------------------------------------------------------------------------------- /app/dictionary.py.words: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # This is a list of non-English words that are in Python libraries. 16 | abspath 17 | addstr 18 | altsep 19 | app 20 | argparse 21 | argtypes 22 | ascii 23 | atime 24 | basename 25 | baudrate 26 | binascii 27 | btab 28 | builtins 29 | bytecode 30 | byteorder 31 | callstats 32 | cantcreat 33 | chdir 34 | chflags 35 | chgat 36 | chmod 37 | chown 38 | chr 39 | closerange 40 | codecs 41 | col 42 | cols 43 | confstr 44 | contextlib 45 | contextmanager 46 | ctermid 47 | ctime 48 | ctrl 49 | ctypes 50 | curdir 51 | dataerr 52 | dedent 53 | def 54 | defpath 55 | del 56 | delitem 57 | delslice 58 | dev 59 | devnull 60 | difflib 61 | dirs 62 | displayhook 63 | dotall 64 | dsync 65 | dup 66 | egginsert 67 | elif 68 | en 69 | endswith 70 | environ 71 | errorpass 72 | exc 73 | excepthook 74 | execlexecle 75 | execlp 76 | execlpe 77 | execv 78 | execve 79 | execvp 80 | execvpe 81 | exlock 82 | expandtabs 83 | expanduser 84 | expandvars 85 | extsep 86 | fchdir 87 | fchmod 88 | fchown 89 | fdopen 90 | fileno 91 | findall 92 | finditer 93 | fnmatch 94 | forkpty 95 | fpathconf 96 | fstat 97 | fstatvfs 98 | fsync 99 | ftruncate 100 | fullmatch 101 | getattr 102 | getch 103 | getcheckinterval 104 | getcwd 105 | getcwdu 106 | getdefaultencoding 107 | getdlopenflags 108 | getegid 109 | getenv 110 | geteuid 111 | getfilesystemencoding 112 | getframe 113 | getgid 114 | getgroups 115 | getitem 116 | getloadavg 117 | getlogin 118 | getmaxyx 119 | getmouse 120 | getmtime 121 | getnev 122 | getpass 123 | getpgid 124 | getpgrp 125 | getpid 126 | getppid 127 | getpreferredencoding 128 | getprofile 129 | getrecursionlimit 130 | getrefcount 131 | getsid 132 | getsize 133 | getsizeof 134 | getslice 135 | gettrace 136 | getuid 137 | getuser 138 | getvalue 139 | getyx 140 | gid 141 | gmem 142 | goto 143 | hasattr 144 | hashlib 145 | hexdigest 146 | hexlify 147 | hexversion 148 | hglobal 149 | hinstance 150 | hmenu 151 | hwnd 152 | iexec 153 | iglob 154 | ignorecase 155 | init 156 | initgroups 157 | ino 158 | insort 159 | inventwithpython 160 | ioerr 161 | isabs 162 | isalnum 163 | isalpha 164 | isatty 165 | isdecimal 166 | isdigit 167 | isdir 168 | isfile 169 | isinstance 170 | islink 171 | islower 172 | ismount 173 | isnumeric 174 | isprint 175 | isspace 176 | issubclass 177 | istitle 178 | isupper 179 | iteritems 180 | itertools 181 | keyname 182 | killpg 183 | klipper 184 | kwargs 185 | kwarning 186 | lchflags 187 | lchmod 188 | lchown 189 | leaveok 190 | len 191 | lft 192 | linesep 193 | listdir 194 | ljust 195 | localtime 196 | lpcstr 197 | lpvoid 198 | lseek 199 | lstat 200 | lstrip 201 | makedev 202 | makedirs 203 | max 204 | maxsize 205 | maxsplit 206 | maxunicode 207 | memmove 208 | metavar 209 | min 210 | mkdir 211 | mkfifo 212 | mknod 213 | mouseinterval 214 | mousemask 215 | moveable 216 | mtime 217 | multiline 218 | mvwin 219 | nargs 220 | ndelay 221 | ndiff 222 | newwin 223 | ngroups 224 | noctty 225 | nofollow 226 | nohost 227 | noinput 228 | nonblock 229 | noperm 230 | normpath 231 | nouser 232 | noutrefresh 233 | nowait 234 | nowaito 235 | npage 236 | nxt 237 | openpty 238 | ord 239 | os 240 | oserr 241 | osfile 242 | pardir 243 | pathconf 244 | pathsep 245 | pbcopy 246 | pbpaste 247 | pid 248 | plen 249 | popen 250 | ppage 251 | pprint 252 | prog 253 | prv 254 | ps 255 | pstats 256 | putenv 257 | pyperclip 258 | pythonpath 259 | qdbus 260 | rdonly 261 | rdwr 262 | re 263 | readlines 264 | readlink 265 | realpath 266 | regex 267 | regs 268 | relpath 269 | removedirs 270 | repl 271 | repr 272 | resizeterm 273 | restype 274 | returncode 275 | rfind 276 | rit 277 | rmdir 278 | rsplit 279 | rstrip 280 | scrollok 281 | sel 282 | sep 283 | setattr 284 | setcheckinterval 285 | setdefault 286 | setdlopenflags 287 | setegid 288 | seteuid 289 | setgid 290 | setgroups 291 | setitem 292 | setlocale 293 | setpgid 294 | setpgrp 295 | setprofile 296 | setrecursionlimit 297 | setregid 298 | setreuid 299 | setsid 300 | setslice 301 | settrace 302 | setuid 303 | shlock 304 | shome 305 | shutil 306 | sigalrm 307 | sighup 308 | sigterm 309 | sigusr 310 | sigwinch 311 | sizeof 312 | sleft 313 | snext 314 | spawnl 315 | spawnle 316 | spawnlp 317 | spawnlpe 318 | spawnv 319 | spawnve 320 | spawnvef 321 | spawnvp 322 | spawnvpe 323 | splitext 324 | splitlines 325 | sprevious 326 | sre 327 | sright 328 | startswith 329 | statvfs 330 | str 331 | strftime 332 | subparsers 333 | symlink 334 | sys 335 | sysconf 336 | tarfile 337 | tcgetpgrp 338 | tcsetpgrp 339 | tempfail 340 | tempfile 341 | tempnam 342 | termios 343 | textwrap 344 | timeit 345 | tiocgwinsz 346 | tmpfile 347 | tmpnam 348 | traceback 349 | trunc 350 | ttyname 351 | uid 352 | umask 353 | uname 354 | ungetch 355 | unhexlify 356 | unichr 357 | unicodetext 358 | unittest 359 | unsetenv 360 | urandom 361 | urllib 362 | urlopen 363 | utime 364 | waitpid 365 | warnoptions 366 | wchar 367 | wcontinued 368 | wcoredump 369 | wexitstatus 370 | wifcontinued 371 | wifexited 372 | wifsignaled 373 | wifstopped 374 | windll 375 | wintypes 376 | wnohang 377 | wronly 378 | wstopsig 379 | wtermsig 380 | wuntraced 381 | xclip 382 | xrange 383 | xsel 384 | zfill 385 | -------------------------------------------------------------------------------- /app/background.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # For Python 2to3 support. 16 | from __future__ import absolute_import 17 | from __future__ import division 18 | from __future__ import print_function 19 | 20 | try: 21 | unicode 22 | except NameError: 23 | unicode = str 24 | unichr = chr 25 | 26 | import os 27 | 28 | try: 29 | import Queue as queue 30 | except ImportError: 31 | import queue 32 | import signal 33 | import sys 34 | import threading 35 | import time 36 | import traceback 37 | 38 | import app.config 39 | import app.profile 40 | import app.render 41 | 42 | 43 | class InstructionQueue(queue.Queue): 44 | def __init__(self, *args, **keywords): 45 | queue.Queue.__init__(self, *args, **keywords) 46 | 47 | def get(self, *args, **keywords): 48 | result = queue.Queue.get(self, *args, **keywords) 49 | if app.config.strict_debug: 50 | assert isinstance(result, tuple), repr(result) 51 | assert isinstance(result[0], unicode), repr(result[0]) 52 | return result[0], result[1] 53 | 54 | def empty(self, *args, **keywords): 55 | # This thread yield (time.sleep(0)) dramatically improves Python3 56 | # performance. Without this line empty() will be called far too often. 57 | time.sleep(0) 58 | return queue.Queue.empty(self, *args, **keywords) 59 | 60 | def put(self, instruction, message): 61 | if app.config.strict_debug: 62 | assert isinstance(instruction, unicode), repr(instruction) 63 | queue.Queue.put(self, (instruction, message)) 64 | 65 | 66 | class BackgroundThread(threading.Thread): 67 | def __init__(self, programWindow, toBackground, fromBackground, *args, **keywords): 68 | threading.Thread.__init__(self, *args, **keywords) 69 | self._programWindow = programWindow 70 | self._toBackground = toBackground 71 | self._fromBackground = fromBackground 72 | 73 | def get(self): 74 | return self._fromBackground.get() 75 | 76 | def has_message(self): 77 | return not self._fromBackground.empty() 78 | 79 | def has_user_event(self): 80 | return not self._toBackground.empty() 81 | 82 | def put(self, instruction, message): 83 | self._toBackground.put(instruction, message) 84 | 85 | def run(self): 86 | cmdCount = 0 87 | block = True 88 | pid = os.getpid() 89 | signalNumber = signal.SIGUSR1 90 | programWindow = self._programWindow 91 | while True: 92 | try: 93 | try: 94 | instruction, message = self._toBackground.get(block) 95 | # profile = app.profile.begin_python_profile() 96 | if instruction == u"quit": 97 | app.log.info("bg received quit message") 98 | return 99 | elif instruction == u"cmdList": 100 | app.log.info(programWindow, message) 101 | programWindow.execute_command_list(message) 102 | else: 103 | assert False, instruction 104 | block = programWindow.short_time_slice() 105 | programWindow.render() 106 | # debugging only: programWindow.show_window_hierarchy() 107 | cmdCount += len(message) 108 | programWindow.program.backgroundFrame.set_cmd_count(cmdCount) 109 | self._fromBackground.put( 110 | u"render", programWindow.program.backgroundFrame.grab_frame() 111 | ) 112 | os.kill(pid, signalNumber) 113 | # app.profile.end_python_profile(profile) 114 | time.sleep(0) # See note in has_message(). 115 | if block or not self._toBackground.empty(): 116 | continue 117 | except queue.Empty: 118 | pass 119 | block = programWindow.long_time_slice() 120 | if block: 121 | programWindow.render() 122 | programWindow.program.backgroundFrame.set_cmd_count(cmdCount) 123 | self._fromBackground.put( 124 | u"render", programWindow.program.backgroundFrame.grab_frame() 125 | ) 126 | os.kill(pid, signalNumber) 127 | except Exception as e: 128 | app.log.exception(e) 129 | app.log.error("bg thread exception", e) 130 | errorType, value, tracebackInfo = sys.exc_info() 131 | out = traceback.format_exception(errorType, value, tracebackInfo) 132 | self._fromBackground.put(u"exception", out) 133 | os.kill(pid, signalNumber) 134 | while True: 135 | instruction, message = self._toBackground.get() 136 | if instruction == u"quit": 137 | app.log.info("bg received quit message") 138 | return 139 | 140 | 141 | def startup_background(programWindow): 142 | toBackground = InstructionQueue() 143 | fromBackground = InstructionQueue() 144 | bg = BackgroundThread(programWindow, toBackground, fromBackground) 145 | bg.setName("ci_edit_bg") 146 | bg.setDaemon(True) 147 | bg.start() 148 | return bg 149 | -------------------------------------------------------------------------------- /app/buffer_manager.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # For Python 2to3 support. 16 | from __future__ import absolute_import 17 | from __future__ import division 18 | from __future__ import print_function 19 | 20 | try: 21 | unicode 22 | except NameError: 23 | unicode = str # redefined-builtin 24 | unichr = chr 25 | 26 | import io 27 | import os 28 | import sys 29 | 30 | import app.buffer_file 31 | import app.config 32 | import app.log 33 | import app.history 34 | import app.text_buffer 35 | 36 | 37 | class BufferManager: 38 | """Manage a set of text buffers. Some text buffers may be hidden.""" 39 | 40 | def __init__(self, program, prefs): 41 | if app.config.strict_debug: 42 | assert issubclass(self.__class__, BufferManager), self 43 | self.program = program 44 | self.prefs = prefs 45 | # Using a dictionary lookup for buffers accelerates finding buffers by 46 | # key (the file path), but that's not the common use. Maintaining an 47 | # ordered list turns out to be more valuable. 48 | self.buffers = [] 49 | 50 | def close_text_buffer(self, textBuffer): 51 | """Warning this will throw away the buffer. Please be sure the user is 52 | ok with this before calling.""" 53 | if app.config.strict_debug: 54 | assert issubclass(self.__class__, BufferManager), self 55 | assert issubclass(textBuffer.__class__, app.text_buffer.TextBuffer) 56 | self.untrack_buffer_(textBuffer) 57 | 58 | def get_unsaved_buffer(self): 59 | for fileBuffer in self.buffers: 60 | if fileBuffer.is_dirty(): 61 | return fileBuffer 62 | return None 63 | 64 | def new_text_buffer(self): 65 | textBuffer = app.text_buffer.TextBuffer(self.program) 66 | self.buffers.append(textBuffer) 67 | app.log.info(textBuffer) 68 | self.debug_log() 69 | return textBuffer 70 | 71 | def next_buffer(self): 72 | app.log.info() 73 | self.debug_log() 74 | if len(self.buffers): 75 | return self.buffers[0] 76 | return None 77 | 78 | def top_buffer(self): 79 | app.log.info() 80 | self.debug_log() 81 | if len(self.buffers): 82 | return self.buffers[-1] 83 | return None 84 | 85 | def get_valid_text_buffer(self, textBuffer): 86 | """If |textBuffer| is a managed buffer return it, otherwise create a new 87 | buffer. Primarily used to determine if a held reference to a textBuffer 88 | is still valid.""" 89 | if textBuffer in self.buffers: 90 | del self.buffers[self.buffers.index(textBuffer)] 91 | self.buffers.append(textBuffer) 92 | return textBuffer 93 | textBuffer = app.text_buffer.TextBuffer(self.program) 94 | self.buffers.append(textBuffer) 95 | return textBuffer 96 | 97 | def load_text_buffer(self, relPath): 98 | if app.config.strict_debug: 99 | assert issubclass(self.__class__, BufferManager), self 100 | assert isinstance(relPath, unicode), type(relPath) 101 | fullPath = app.buffer_file.expand_full_path(relPath) 102 | app.log.info(fullPath) 103 | textBuffer = None 104 | for i, tb in enumerate(self.buffers): 105 | if tb.fullPath == fullPath: 106 | textBuffer = tb 107 | del self.buffers[i] 108 | self.buffers.append(tb) 109 | break 110 | app.log.info(u"Searched for textBuffer", repr(textBuffer)) 111 | if not textBuffer: 112 | if os.path.isdir(fullPath): 113 | app.log.info(u"Tried to open directory as a file", fullPath) 114 | return 115 | if not os.path.isfile(fullPath): 116 | app.log.info(u"creating a new file at\n ", fullPath) 117 | textBuffer = app.text_buffer.TextBuffer(self.program) 118 | textBuffer.set_file_path(fullPath) 119 | textBuffer.file_load() 120 | self.buffers.append(textBuffer) 121 | if 0: 122 | self.debug_log() 123 | return textBuffer 124 | 125 | def debug_log(self): 126 | bufferList = u"" 127 | for i in self.buffers: 128 | bufferList += u"\n " + repr(i.fullPath) 129 | bufferList += u"\n " + repr(i) 130 | bufferList += u"\n dirty: " + str(i.is_dirty()) 131 | app.log.info(u"BufferManager" + bufferList) 132 | 133 | def read_stdin(self): 134 | app.log.info(u"reading from stdin") 135 | # Create a new input stream for the file data. 136 | # Fd is short for file descriptor. os.dup and os.dup2 will duplicate 137 | # file descriptors. 138 | stdinFd = sys.stdin.fileno() 139 | newFd = os.dup(stdinFd) 140 | newStdin = io.open(u"/dev/tty") 141 | os.dup2(newStdin.fileno(), stdinFd) 142 | # Create a text buffer to read from alternate stream. 143 | textBuffer = self.new_text_buffer() 144 | try: 145 | with io.open(newFd, u"r") as fileInput: 146 | textBuffer.file_filter(fileInput.read()) 147 | except Exception as e: 148 | app.log.exception(e) 149 | app.log.info(u"finished reading from stdin") 150 | return textBuffer 151 | 152 | def untrack_buffer_(self, fileBuffer): 153 | app.log.debug(fileBuffer.fullPath) 154 | self.buffers.remove(fileBuffer) 155 | 156 | def file_close(self, path): 157 | pass 158 | -------------------------------------------------------------------------------- /unit_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright 2016 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from __future__ import absolute_import 18 | from __future__ import division 19 | from __future__ import print_function 20 | 21 | import os 22 | import sys 23 | 24 | if not os.getenv("CI_EDIT_USE_REAL_CURSES"): 25 | # Replace curses with a fake version for testing. 26 | sys.path = [os.path.join(os.path.dirname(__file__), "test_fake")] + sys.path 27 | import app.log 28 | 29 | app.log.enabledChannels = { 30 | "error": True, 31 | "info": True, 32 | "meta": True, 33 | "mouse": True, 34 | "startup": True, 35 | } 36 | app.log.shouldWritePrintLog = True 37 | 38 | import unittest 39 | 40 | # Set up strict_debug before loading other app.* modules. 41 | import app.config 42 | 43 | app.config.strict_debug = True 44 | 45 | import app.unit_test_actions 46 | import app.unit_test_application 47 | import app.unit_test_automatic_column_adjustment 48 | import app.unit_test_bookmarks 49 | import app.unit_test_brace_matching 50 | import app.unit_test_buffer_file 51 | import app.unit_test_copy_paste 52 | import app.unit_test_curses_util 53 | import app.unit_test_execute_prompt 54 | import app.unit_test_file_manager 55 | import app.unit_test_find_window 56 | import app.unit_test_intention 57 | import app.unit_test_line_buffer 58 | import app.unit_test_misspellings 59 | import app.unit_test_parser 60 | import app.unit_test_performance 61 | import app.unit_test_prediction_window 62 | import app.unit_test_prefs 63 | import app.unit_test_regex 64 | import app.unit_test_selectable 65 | import app.unit_test_startup 66 | import app.unit_test_string 67 | import app.unit_test_text_buffer 68 | import app.unit_test_ui 69 | import app.unit_test_undo_redo 70 | 71 | # Add new test cases here. 72 | TESTS = { 73 | "actions_grammar": app.unit_test_actions.GrammarDeterminationTestCases, 74 | "actions_mouse": app.unit_test_actions.MouseTestCases, 75 | "actions_selection": app.unit_test_actions.SelectionTestCases, 76 | "actions_text_indent": app.unit_test_actions.TextIndentTestCases, 77 | "actions_text_insert": app.unit_test_actions.TextInsertTestCases, 78 | "application": app.unit_test_application.ApplicationTestCases, 79 | "automatic_column_adjustment": app.unit_test_automatic_column_adjustment.AutomaticColumnAdjustmentCases, 80 | "bookmarks": app.unit_test_bookmarks.BookmarkTestCases, 81 | "brace_matching": app.unit_test_brace_matching.BraceMatchingTestCases, 82 | "buffer_file": app.unit_test_buffer_file.pathRowColumnTestCases, 83 | "copy_paste": app.unit_test_copy_paste.CopyPasteTestCases, 84 | "curses_util": app.unit_test_curses_util.CursesUtilTestCases, 85 | "file_manager": app.unit_test_file_manager.FileManagerTestCases, 86 | "find": app.unit_test_find_window.FindWindowTestCases, 87 | "execute": app.unit_test_execute_prompt.ExecutePromptTestCases, 88 | "intention": app.unit_test_intention.IntentionTestCases, 89 | "line_buffer": app.unit_test_line_buffer.LineBufferTestCases, 90 | "misspellings": app.unit_test_misspellings.MisspellingsTestCases, 91 | "parser": app.unit_test_parser.ParserTestCases, 92 | "performance": app.unit_test_performance.PerformanceTestCases, 93 | "prediction": app.unit_test_prediction_window.PredictionWindowTestCases, 94 | "prefs": app.unit_test_prefs.PrefsTestCases, 95 | "regex": app.unit_test_regex.RegexTestCases, 96 | "selectable": app.unit_test_selectable.SelectableTestCases, 97 | "startup": app.unit_test_startup.StartupTestCases, 98 | "string": app.unit_test_string.StringTestCases, 99 | "draw": app.unit_test_text_buffer.DrawTestCases, 100 | "ui": app.unit_test_ui.UiBasicsTestCases, 101 | "undo": app.unit_test_undo_redo.UndoRedoTestCases, 102 | } 103 | 104 | 105 | def run_tests(tests, stopOnFailure=False): 106 | """Run through the list of tests.""" 107 | for test in tests: 108 | suite = unittest.TestLoader().loadTestsFromTestCase(test) 109 | result = unittest.TextTestRunner(verbosity=2).run(suite) 110 | if stopOnFailure and (result.failures or result.errors): 111 | return 1 112 | return 0 113 | 114 | 115 | def usage(): 116 | print("Help:") 117 | print("./unit_tests.py [--log] [[no] ]\n") 118 | print(" --help This help") 119 | print(" --log Print output from app.log.* calls") 120 | print(" no Run all tests except named tests") 121 | print(" Run the named set of tests (only)") 122 | print("The argument is any of:") 123 | testNames = list(TESTS.keys()) 124 | testNames.sort() 125 | for i in testNames: 126 | print(" ", i) 127 | 128 | 129 | def parse_arg_list(argList): 130 | testList = list(TESTS.values()) 131 | try: 132 | argList.remove("--help") 133 | usage() 134 | sys.exit(0) 135 | except ValueError: 136 | pass 137 | try: 138 | useAppLog = False 139 | argList.remove("--log") 140 | useAppLog = True 141 | except ValueError: 142 | pass 143 | if len(argList) > 1: 144 | if not (argList[1] == u"no" or argList[1] in TESTS): 145 | usage() 146 | sys.exit(-1) 147 | if argList[1] == u"no": 148 | for i in argList[2:]: 149 | del testList[testList.index(TESTS[i])] 150 | else: 151 | testList = [] 152 | for i in argList[1:]: 153 | testList.append(TESTS[i]) 154 | if useAppLog: 155 | app.log.wrapper(lambda: run_tests(testList, True)) 156 | else: 157 | sys.exit(run_tests(testList, True)) 158 | 159 | 160 | if __name__ == "__main__": 161 | parse_arg_list(sys.argv) 162 | -------------------------------------------------------------------------------- /app/unit_test_text_buffer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | import unittest 20 | 21 | from app.curses_util import * 22 | import app.fake_curses_testing 23 | 24 | 25 | class DrawTestCases(app.fake_curses_testing.FakeCursesTestCase): 26 | def setUp(self): 27 | app.fake_curses_testing.FakeCursesTestCase.set_up(self) 28 | 29 | def test_draw_nothing(self): 30 | self.run_with_fake_inputs( 31 | [ 32 | self.display_check(2, 7, [u" "]), 33 | self.write_text(u"tex"), 34 | self.display_check(2, 7, [u"tex "]), 35 | KEY_BACKSPACE1, 36 | u"t", 37 | self.display_check(2, 7, [u"tet "]), 38 | CTRL_Q, 39 | u"n", 40 | ] 41 | ) 42 | 43 | def test_draw_tabs(self): 44 | test = u"""\t\t< 50 | \t\t<2tabs 51 | line\twith\ttabs 52 | ends with tab>\t 53 | \t 54 | """ 55 | self.run_with_fake_inputs( 56 | [ 57 | self.display_check(2, 7, [u" "]), 58 | self.write_text(test), 59 | self.display_check(2, 7, [u" < "]), 65 | self.display_check(8, 7, [u" <2tabs "]), 66 | self.display_check(9, 7, [u"line with tabs "]), 67 | self.display_check(10, 7, [u"ends with tab> "]), 68 | self.display_check(11, 7, [u" "]), 69 | CTRL_Q, 70 | u"n", 71 | ] 72 | ) 73 | 74 | def test_draw_text(self): 75 | self.run_with_fake_inputs( 76 | [ 77 | self.display_check(2, 7, [u" "]), 78 | self.write_text(u"text"), 79 | self.display_check(2, 7, [u"text "]), 80 | CTRL_Q, 81 | u"n", 82 | ] 83 | ) 84 | 85 | def test_draw_long_line(self): 86 | # self.set_movie_mode(True) 87 | lineLimitIndicator = self.prg.prefs.editor["lineLimitIndicator"] 88 | self.prg.prefs.editor["lineLimitIndicator"] = 10 89 | self.run_with_fake_inputs( 90 | [ 91 | self.display_check(2, 7, [u" "]), 92 | self.write_text(u"A line with numbers 1234567890"), 93 | self.display_check(2, 7, [u"A line with numbers 1234567890"]), 94 | self.write_text(u". Writing"), 95 | self.display_check(2, 7, [u"ith numbers 1234567890. Writing"]), 96 | self.write_text(u" some more."), 97 | self.display_check(2, 7, [u" 1234567890. Writing some more."]), 98 | self.write_text(u"\n"), 99 | self.display_check(2, 7, [u"A line with numbers 1234567890."]), 100 | CTRL_Q, 101 | u"n", 102 | ] 103 | ) 104 | self.prg.prefs.editor["lineLimitIndicator"] = lineLimitIndicator 105 | 106 | def test_draw_line_endings(self): 107 | # self.set_movie_mode(True) 108 | assert self.prg.color.get(u"text", 0) != self.prg.color.get(u"selected", 0) 109 | self.run_with_fake_inputs( 110 | [ 111 | self.display_check(2, 7, [u" "]), 112 | self.write_text(u"text\none\ntwo\nthree\n"), 113 | self.display_check(2, 7, [u"text ", u"one ", u"two ", u"three "]), 114 | self.display_check_style(2, 7, 4, 10, self.prg.color.get(u"text", 0)), 115 | self.selection_check(4, 0, 0, 0, 0), 116 | KEY_UP, 117 | KEY_UP, 118 | KEY_UP, 119 | KEY_UP, 120 | KEY_RIGHT, 121 | KEY_SHIFT_RIGHT, 122 | self.selection_check(0, 2, 0, 1, 3), 123 | self.display_check_style(2, 7, 1, 1, self.prg.color.get(u"text", 0)), 124 | self.display_check_style( 125 | 2, 8, 1, 1, self.prg.color.get(u"selected", 0) 126 | ), 127 | self.display_check_style(2, 9, 1, 3, self.prg.color.get(u"text", 0)), 128 | KEY_SHIFT_RIGHT, 129 | KEY_SHIFT_RIGHT, 130 | KEY_SHIFT_RIGHT, 131 | KEY_SHIFT_RIGHT, 132 | self.display_check_style(2, 7, 1, 1, self.prg.color.get(u"text", 0)), 133 | self.display_check_style( 134 | 2, 8, 1, 4, self.prg.color.get(u"selected", 0) 135 | ), 136 | self.display_check_style( 137 | 3, 7, 1, 1, self.prg.color.get(u"selected", 0) 138 | ), 139 | KEY_SHIFT_RIGHT, 140 | KEY_SHIFT_RIGHT, 141 | KEY_SHIFT_RIGHT, 142 | KEY_SHIFT_RIGHT, 143 | self.display_check_style(2, 7, 1, 1, self.prg.color.get(u"text", 0)), 144 | self.display_check_style( 145 | 2, 8, 1, 4, self.prg.color.get(u"selected", 0) 146 | ), 147 | self.display_check_style( 148 | 3, 7, 1, 4, self.prg.color.get(u"selected", 0) 149 | ), 150 | CTRL_Q, 151 | u"n", 152 | ] 153 | ) 154 | -------------------------------------------------------------------------------- /app/unit_test_copy_paste.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright 2019 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from __future__ import absolute_import 18 | from __future__ import division 19 | from __future__ import print_function 20 | 21 | import curses 22 | import os 23 | import sys 24 | 25 | from app.curses_util import * 26 | import app.ci_program 27 | import app.curses_util 28 | import app.fake_curses_testing 29 | 30 | kTestFile = u"#application_test_file_with_unlikely_file_name~" 31 | 32 | 33 | class CopyPasteTestCases(app.fake_curses_testing.FakeCursesTestCase): 34 | def setUp(self): 35 | self.longMessage = True 36 | app.fake_curses_testing.FakeCursesTestCase.set_up(self) 37 | 38 | def test_bracketed_paste(self): 39 | self.assertEqual(app.curses_util.char_width(u"ế", 0), 1) 40 | self.run_with_fake_inputs( 41 | [ 42 | self.display_check(2, 7, [u" "]), 43 | curses.ascii.ESC, 44 | app.curses_util.BRACKETED_PASTE_BEGIN, 45 | u"t", 46 | u"e", 47 | 225, 48 | 186, 49 | 191, # Send an "" in utf-8. 50 | u"t", 51 | curses.ascii.ESC, 52 | app.curses_util.BRACKETED_PASTE_END, 53 | self.display_check(2, 7, [u"te\u1ebft "]), 54 | CTRL_Q, 55 | u"n", 56 | ] 57 | ) 58 | 59 | def test_cut_paste_undo_redo(self): 60 | # self.set_movie_mode(True) 61 | self.run_with_fake_inputs( 62 | [ 63 | self.display_check(2, 7, [u" "]), 64 | self.write_text(u"apple\nbanana\ncarrot\ndate\neggplant\nfig"), 65 | self.display_check( 66 | 2, 67 | 7, 68 | [ 69 | u"apple ", 70 | u"banana ", 71 | u"carrot ", 72 | u"date ", 73 | u"eggplant ", 74 | u"fig ", 75 | u" ", 76 | ], 77 | ), 78 | self.selection_check(5, 3, 0, 0, 0), 79 | KEY_UP, 80 | KEY_UP, 81 | KEY_SHIFT_UP, 82 | KEY_SHIFT_UP, 83 | KEY_SHIFT_LEFT, 84 | self.selection_check(1, 2, 3, 3, 3), 85 | CTRL_X, 86 | self.display_check( 87 | 2, 88 | 7, 89 | [ 90 | u"apple ", 91 | u"bae ", 92 | u"eggplant ", 93 | u"fig ", 94 | u" ", 95 | ], 96 | ), 97 | self.selection_check(1, 2, 1, 2, 0), 98 | CTRL_V, 99 | self.display_check( 100 | 2, 101 | 7, 102 | [ 103 | u"apple ", 104 | u"banana ", 105 | u"carrot ", 106 | u"date ", 107 | u"eggplant ", 108 | u"fig ", 109 | u" ", 110 | ], 111 | ), 112 | self.selection_check(3, 3, 1, 2, 0), 113 | CTRL_V, 114 | self.display_check( 115 | 2, 116 | 7, 117 | [ 118 | u"apple ", 119 | u"banana ", 120 | u"carrot ", 121 | u"datnana ", 122 | u"carrot ", 123 | u"date ", 124 | u"eggplant ", 125 | u"fig ", 126 | u" ", 127 | ], 128 | ), 129 | self.selection_check(5, 3, 1, 2, 0), 130 | CTRL_Z, 131 | self.display_check( 132 | 2, 133 | 7, 134 | [ 135 | u"apple ", 136 | u"banana ", 137 | u"carrot ", 138 | u"date ", 139 | u"eggplant ", 140 | u"fig ", 141 | u" ", 142 | ], 143 | ), 144 | self.selection_check(3, 3, 1, 2, 0), 145 | CTRL_Z, 146 | self.display_check( 147 | 2, 148 | 7, 149 | [ 150 | u"apple ", 151 | u"bae ", 152 | u"eggplant ", 153 | u"fig ", 154 | u" ", 155 | ], 156 | ), 157 | self.selection_check(1, 2, 1, 2, 0), 158 | CTRL_Y, 159 | CTRL_Y, 160 | self.display_check( 161 | 2, 162 | 7, 163 | [ 164 | u"apple ", 165 | u"banana ", 166 | u"carrot ", 167 | u"datnana ", 168 | u"carrot ", 169 | u"date ", 170 | u"eggplant ", 171 | u"fig ", 172 | u" ", 173 | ], 174 | ), 175 | self.selection_check(5, 3, 1, 2, 0), 176 | CTRL_Q, 177 | u"n", 178 | ] 179 | ) 180 | 181 | def test_write_text(self): 182 | self.run_with_fake_inputs([self.write_text(u"test\n"), CTRL_Q, u"n"]) 183 | -------------------------------------------------------------------------------- /app/dictionary.cpp.words: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # This is a list of non-English words that are in the C++ programming language 16 | # libraries. 17 | acosh 18 | addrstrlen 19 | af 20 | alloca 21 | asctime 22 | asin 23 | asinh 24 | asprintf 25 | atan 26 | atanh 27 | atexit 28 | atof 29 | atoi 30 | atol 31 | badbit 32 | beg 33 | bitset 34 | bmstate 35 | boolalpha 36 | bsearch 37 | btowc 38 | calloc 39 | cassert 40 | cbegin 41 | ccomplex 42 | cctype 43 | ceil 44 | cend 45 | cerr 46 | cin 47 | clearerr 48 | climits 49 | closedir 50 | cmath 51 | conio 52 | copyfmt 53 | countof 54 | cout 55 | cplusplus 56 | crbegin 57 | creat 58 | crend 59 | cstddef 60 | cstdio 61 | cstdlib 62 | cstream 63 | cstring 64 | ctime 65 | ctype 66 | cur 67 | cv 68 | cwctype 69 | decltype 70 | declval 71 | demangle 72 | dfl 73 | dgram 74 | difftime 75 | dirent 76 | dprintf 77 | eagain 78 | ebadf 79 | eexist 80 | eintr 81 | einval 82 | endl 83 | enobufs 84 | enomem 85 | enotdir 86 | epollin 87 | errnum 88 | etimedout 89 | etimeout 90 | ewouldblock 91 | extern 92 | failbit 93 | fclose 94 | feof 95 | ferror 96 | fflush 97 | fgetc 98 | fgetpos 99 | fgets 100 | fgetwc 101 | fgetws 102 | filebuf 103 | fileno 104 | fmt 105 | fmtflags 106 | fopen 107 | fp 108 | fpos 109 | fprintf 110 | fputc 111 | fputs 112 | fputwc 113 | fputws 114 | fread 115 | freeifaddrs 116 | freopen 117 | fscanf 118 | fseek 119 | fsetpos 120 | fstat 121 | fstream 122 | ftell 123 | ftruncate 124 | fwide 125 | fwprintf 126 | fwrite 127 | fwscanf 128 | gcount 129 | getc 130 | getchar 131 | getenv 132 | getfl 133 | getifaddrs 134 | getline 135 | getopt 136 | gettimeofday 137 | getwc 138 | getwchar 139 | gflags 140 | gmtime 141 | grpc 142 | gteq 143 | htons 144 | icrnl 145 | ifaddrs 146 | iflag 147 | ifstream 148 | ign 149 | imag 150 | inpck 151 | inplace 152 | intmax 153 | intptr 154 | intrinsics 155 | inttypes 156 | iomanip 157 | iosfwd 158 | iostream 159 | ipproto 160 | irgrp 161 | iroth 162 | irusr 163 | isalnum 164 | isalpha 165 | isatty 166 | isblank 167 | iscntrl 168 | isdigit 169 | isgraph 170 | islower 171 | isprint 172 | ispunct 173 | isspace 174 | istream 175 | istreambuf 176 | istringstream 177 | istrip 178 | isupper 179 | iswalnum 180 | iswalpha 181 | iswblank 182 | iswcntrl 183 | iswctype 184 | iswdigit 185 | iswgraph 186 | iswlower 187 | iswprint 188 | iswpunct 189 | iswspace 190 | iswupper 191 | iswxdigit 192 | isxdigit 193 | itoa 194 | iword 195 | iwusr 196 | ixon 197 | jmp 198 | lc 199 | lconv 200 | ldiv 201 | libcpp 202 | llabs 203 | lldiv 204 | localeconv 205 | localtime 206 | longjmp 207 | lseek 208 | lteq 209 | lu 210 | malloc 211 | mblen 212 | mbrlen 213 | mbrtowc 214 | mbsinit 215 | mbsrtowcs 216 | mbstowcs 217 | mbtowc 218 | memchr 219 | memcmp 220 | memcpy 221 | memmove 222 | memset 223 | minmax 224 | mkdir 225 | mktime 226 | multimap 227 | ncurses 228 | noboolalpha 229 | noexcept 230 | nonblock 231 | noreturn 232 | noshowbase 233 | noshowpoint 234 | noshowpos 235 | noskipws 236 | nothrow 237 | nounitbuf 238 | nouppercase 239 | nowait 240 | npos 241 | ntoa 242 | ntohl 243 | ntohs 244 | nullopt 245 | nullptr 246 | offsetof 247 | oflag 248 | ofstream 249 | opendir 250 | openmode 251 | opost 252 | ord 253 | ostream 254 | ostringstream 255 | pbackfail 256 | perror 257 | pollerr 258 | pollfd 259 | pollin 260 | pollnval 261 | pollout 262 | pollpri 263 | pollrdhup 264 | ppoll 265 | printf 266 | pton 267 | ptrdiff 268 | putc 269 | putchar 270 | putwc 271 | putwchar 272 | pword 273 | qsort 274 | rapidjson 275 | rbegin 276 | rcvtimeo 277 | rdbuf 278 | rdonly 279 | rdstate 280 | rdwr 281 | readdir 282 | recv 283 | recvfrom 284 | refcounted 285 | resetiosflags 286 | ret 287 | rfind 288 | scanf 289 | seekdir 290 | seekg 291 | seekoff 292 | seekp 293 | seekpos 294 | sendto 295 | setbase 296 | setbuf 297 | setenv 298 | setf 299 | setfill 300 | setfl 301 | setg 302 | setiosflags 303 | setjmp 304 | setlocale 305 | setp 306 | setpercision 307 | setprecision 308 | setsockopt 309 | setstate 310 | setvbuf 311 | setw 312 | showbase 313 | showmanyc 314 | showpoint 315 | showpos 316 | sigabrt 317 | sigfpe 318 | sigill 319 | sigint 320 | sigsegv 321 | sigterm 322 | skipws 323 | snprintf 324 | sockaddr 325 | socklen 326 | sprintf 327 | sqrt 328 | srand 329 | ss 330 | sscanf 331 | ssize 332 | sstream 333 | std 334 | stdarg 335 | stdbool 336 | stddef 337 | stdint 338 | stdlib 339 | stoi 340 | stoull 341 | strcat 342 | strchr 343 | strcmp 344 | strcoll 345 | strcpy 346 | strcspn 347 | strdup 348 | streambuf 349 | streamoff 350 | streampos 351 | streamsize 352 | strerror 353 | strftime 354 | stricmp 355 | stringstream 356 | strlcat 357 | strlcpy 358 | strlen 359 | strncat 360 | strncmp 361 | strncpy 362 | strpbrk 363 | strrchr 364 | strspn 365 | strstr 366 | strtod 367 | strtof 368 | strtol 369 | strtold 370 | strtoll 371 | strtoul 372 | strtoull 373 | strxfrm 374 | swprintf 375 | swscanf 376 | tcgetattr 377 | tcsaflush 378 | tcsetattr 379 | tellg 380 | tellp 381 | termios 382 | timeradd 383 | timerclear 384 | timercmp 385 | timerisset 386 | timersub 387 | timespec 388 | timeval 389 | tm 390 | tmpfile 391 | tmpnam 392 | tolower 393 | toupper 394 | towctrans 395 | towlower 396 | towupper 397 | trunc 398 | typeindex 399 | typeinfo 400 | typename 401 | uflow 402 | uint 403 | uintmax 404 | ull 405 | ullong 406 | ungetwc 407 | unistd 408 | unsetf 409 | usleep 410 | va 411 | valarray 412 | vasprintf 413 | vdprintf 414 | vfprintf 415 | vfscanf 416 | vfwprintf 417 | vfwscanf 418 | vprintf 419 | vscanf 420 | vsnprintf 421 | vsprintf 422 | vsscanf 423 | vswprintf 424 | vswscanf 425 | vwprintf 426 | vwscanf 427 | wchar 428 | wcrtomb 429 | wcscat 430 | wcschr 431 | wcscmp 432 | wcscoll 433 | wcscpy 434 | wcscspn 435 | wcsftime 436 | wcslen 437 | wcsncat 438 | wcsncmp 439 | wcsncpy 440 | wcspbrk 441 | wcsrchr 442 | wcsrtombs 443 | wcsspn 444 | wcsstr 445 | wcstod 446 | wcstof 447 | wcstok 448 | wcstol 449 | wcstold 450 | wcstombs 451 | wcsxfrm 452 | wctob 453 | wctomb 454 | wctrans 455 | wctype 456 | weof 457 | wfilebuf 458 | wfstream 459 | wifstream 460 | wmemchr 461 | wmemcmp 462 | wmemcpy 463 | wmemmove 464 | wmemset 465 | wofstream 466 | wprintf 467 | wronly 468 | wscanf 469 | wstreampos 470 | xalloc 471 | -------------------------------------------------------------------------------- /rust/src/ci_program.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::io::Write; 16 | //use std::rc::{Rc, Weak}; 17 | //use std::cell::RefCell; 18 | use super::buffer_manager::BufferManager; 19 | use super::color::Colors; 20 | use super::prefs::Prefs; 21 | use std::cmp::min; 22 | use std::sync::atomic::{AtomicBool, Ordering}; 23 | use std::sync::{Arc, Mutex, RwLock}; 24 | 25 | extern crate ncurses; // https://crates.io/crates/ncurses 26 | 27 | const KEY_CTRL_Q: i32 = 17; 28 | 29 | // Helper function to initialize an MEVENT. (Is there a better approach?) 30 | pub fn newMevent() -> ncurses::ll::MEVENT { 31 | ncurses::ll::MEVENT { 32 | id: 0, 33 | x: 0, 34 | y: 0, 35 | z: 0, 36 | bstate: 0, 37 | } 38 | } 39 | 40 | // A few helpful pieces of data to display in the debug window. 41 | pub struct DebugInfo { 42 | mouse_event: ncurses::ll::MEVENT, 43 | pub ch: i32, 44 | } 45 | 46 | impl DebugInfo { 47 | pub fn new() -> DebugInfo { 48 | DebugInfo { 49 | mouse_event: newMevent(), 50 | ch: 0, 51 | } 52 | } 53 | } 54 | 55 | // This is the overall program singleton that holds the other important 56 | // singletons such as the buffer_manager, preferences, and UI display. 57 | pub struct CiProgram { 58 | buffer_manager: Mutex, 59 | color: RwLock, 60 | prefs: RwLock, 61 | exiting: AtomicBool, 62 | curses_screen: ncurses::WINDOW, 63 | pub debug_info: Mutex, 64 | } 65 | 66 | impl CiProgram { 67 | pub fn new() -> Arc { 68 | let prefs = Prefs::new(); 69 | let program = Arc::new(CiProgram { 70 | buffer_manager: Mutex::new(BufferManager::new()), 71 | color: RwLock::new(Colors::new(prefs.color256.clone())), 72 | prefs: RwLock::new(prefs), 73 | debug_info: Mutex::new(DebugInfo::new()), 74 | exiting: AtomicBool::new(false), 75 | curses_screen: ncurses::initscr(), 76 | }); 77 | program 78 | } 79 | 80 | pub fn init(&self) { 81 | // Maybe set to "en_US.UTF-8"? 82 | ncurses::setlocale(ncurses::LcCategory::all, ""); 83 | 84 | ncurses::raw(); 85 | ncurses::mousemask(ncurses::ALL_MOUSE_EVENTS as ncurses::mmask_t, None); 86 | ncurses::keypad(ncurses::stdscr(), true); 87 | ncurses::meta(ncurses::stdscr(), true); 88 | ncurses::noecho(); 89 | enable_bracketed_paste().expect("enable_bracketed_paste failed"); 90 | ncurses::start_color(); 91 | ncurses::timeout(10); 92 | let curses_window = self.curses_screen; 93 | ncurses::leaveok(curses_window, true); // Don't update cursor position. 94 | ncurses::scrollok(curses_window, true); 95 | ncurses::keypad(curses_window, true); 96 | //app.window.mainCursesWindow = curses_window 97 | } 98 | 99 | pub fn command_loop(&self) { 100 | ncurses::clear(); 101 | ncurses::mv(0, 0); 102 | ncurses::printw("This is a work in progress\n"); 103 | ncurses::printw("Press ctrl+q to exit.\n"); 104 | let mut mouse_event = newMevent(); 105 | while self.exiting.load(Ordering::SeqCst) == false { 106 | let c = ncurses::getch(); 107 | if c == 409 { 108 | let _err = ncurses::getmouse(&mut mouse_event); 109 | } 110 | { 111 | let mut info = self.debug_info.lock().unwrap(); 112 | info.ch = c; 113 | info.mouse_event = mouse_event; 114 | } 115 | if c == KEY_CTRL_Q { 116 | self.quit_now(); 117 | } 118 | if c >= 0 { 119 | // This grabs the mutex separately because this code will be in 120 | // a separate thread later (and I'm getting the hang of rust 121 | // mutex). 122 | let info = self.debug_info.lock().unwrap(); 123 | ncurses::printw(&format!("pressed {}\n", info.ch)); 124 | if c == 409 { 125 | ncurses::printw(&format!("mouse {:?}\n", info.mouse_event)); 126 | } 127 | } 128 | } 129 | ncurses::endwin(); 130 | } 131 | 132 | pub fn parse_args(&self) { 133 | let debugRedo = false; 134 | let showLogWindow = false; 135 | let cliFiles: Vec; 136 | //let cliFiles = vec![]; 137 | let openToLine: Option = None; 138 | let profile = false; 139 | let readStdin = false; 140 | let takeAll = false; // Take all args as file paths. 141 | let timeStartup = false; 142 | let numColors = min(ncurses::COLORS(), 256); 143 | println!("{:?}", self.prefs); 144 | if std::env::var("CI_EDIT_SINGLE_THREAD").is_ok() { 145 | self.prefs 146 | .write() 147 | .unwrap() 148 | .editor 149 | .insert("useBgThread".to_string(), "false".to_string()); 150 | } 151 | } 152 | 153 | pub fn quit_now(&self) { 154 | self.exiting.store(true, Ordering::SeqCst); 155 | } 156 | 157 | pub fn run(&self) { 158 | self.init(); 159 | 160 | self.parse_args(); 161 | self.set_up_palette(); 162 | self.command_loop(); 163 | ncurses::endwin(); 164 | } 165 | 166 | pub fn set_up_palette(&self) {} 167 | } 168 | 169 | fn enable_bracketed_paste() -> std::io::Result<()> { 170 | // Enable Bracketed Paste Mode. 171 | let stdout = std::io::stdout(); 172 | let mut stdout_handle = stdout.lock(); 173 | stdout_handle.write(b"\033[?2004;h")?; 174 | // Push the escape codes out to the terminal. (Whether this is needed seems 175 | // to vary by platform). 176 | stdout_handle.flush()?; 177 | return Ok(()); 178 | } 179 | 180 | pub fn run_ci() { 181 | // Reduce the delay waiting for escape sequences. 182 | std::env::set_var("ESCDELAY", "1"); 183 | let ci_program = CiProgram::new(); 184 | ci_program.run(); 185 | } 186 | --------------------------------------------------------------------------------