├── app
├── .gitignore
├── src
│ └── main
│ │ ├── assets
│ │ ├── cld
│ │ ├── Makefile
│ │ │ ├── termuc.json
│ │ │ └── Makefile
│ │ ├── Clang++
│ │ │ └── termuc.json
│ │ ├── CMake
│ │ │ ├── CMakeLists.txt
│ │ │ └── termuc.json
│ │ ├── fmt
│ │ └── init
│ │ ├── res
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── values-night
│ │ │ └── styles.xml
│ │ ├── values
│ │ │ ├── dimens.xml
│ │ │ ├── colors.xml
│ │ │ ├── ids.xml
│ │ │ └── styles.xml
│ │ ├── values-land
│ │ │ └── dimens.xml
│ │ ├── layout
│ │ │ ├── edit.xml
│ │ │ ├── header_item.xml
│ │ │ ├── editfrag.xml
│ │ │ ├── search_action.xml
│ │ │ ├── file_item.xml
│ │ │ ├── header_dropdown_item.xml
│ │ │ ├── replace.xml
│ │ │ ├── new_project.xml
│ │ │ ├── list_header.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── var_item.xml
│ │ │ ├── debug_controller.xml
│ │ │ ├── key_panel.xml
│ │ │ └── debug_panel.xml
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── drawable
│ │ │ ├── ic_play_24.xml
│ │ │ ├── ic_chevron_left_24.xml
│ │ │ ├── ic_chevron_right_24.xml
│ │ │ ├── key_panel.xml
│ │ │ ├── ic_code_24.xml
│ │ │ ├── ic_folder_24.xml
│ │ │ ├── ic_file_24.xml
│ │ │ ├── ic_redo_24.xml
│ │ │ ├── ic_undo_24.xml
│ │ │ ├── ic_launcher_background.xml
│ │ │ └── ic_find_replace_24.xml
│ │ ├── values-v26
│ │ │ └── strings.xml
│ │ ├── menu
│ │ │ ├── search.xml
│ │ │ └── main.xml
│ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ ├── layout-land
│ │ │ └── activity_main.xml
│ │ ├── xml
│ │ │ └── settings.xml
│ │ └── values-zh
│ │ │ └── strings.xml
│ │ ├── java
│ │ └── cn
│ │ │ └── rbc
│ │ │ └── termuc
│ │ │ ├── FileItem.java
│ │ │ ├── HeaderAdapter.java
│ │ │ ├── FileActivity.java
│ │ │ ├── Application.java
│ │ │ ├── FileAdapter.java
│ │ │ ├── Project.java
│ │ │ ├── SearchAction.java
│ │ │ └── SettingsActivity.java
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
└── build.gradle
├── codeeditor
├── .gitignore
├── consumer-rules.pro
├── src
│ └── main
│ │ ├── assets
│ │ └── codicon.ttf
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── cn
│ │ │ └── rbc
│ │ │ └── codeeditor
│ │ │ ├── util
│ │ │ ├── Range.java
│ │ │ ├── ErrSpan.java
│ │ │ ├── Pair.java
│ │ │ ├── Flag.java
│ │ │ ├── ProgressObserver.java
│ │ │ ├── Lexer.java
│ │ │ ├── CharSeqReader.java
│ │ │ ├── TextWarriorException.java
│ │ │ ├── ProgressSource.java
│ │ │ ├── HelperUtils.java
│ │ │ ├── SearchStrategy.java
│ │ │ ├── DLog.java
│ │ │ ├── TextBufferCache.java
│ │ │ ├── GapIntSet.java
│ │ │ ├── FindThread.java
│ │ │ └── LinearSearchStrategy.java
│ │ │ ├── common
│ │ │ ├── OnCaretScrollListener.java
│ │ │ ├── OnRowChangedListener.java
│ │ │ ├── OnSelectionChangedListener.java
│ │ │ ├── OnKeyShortcutListener.java
│ │ │ └── OnTextChangeListener.java
│ │ │ ├── lang
│ │ │ ├── Formatter.java
│ │ │ ├── DefFormatter.java
│ │ │ ├── xml
│ │ │ │ └── XMLLanguage.java
│ │ │ ├── LanguageJava.java
│ │ │ ├── LanguageJavascript.java
│ │ │ ├── LanguageObjectiveC.java
│ │ │ ├── LanguageNonProg.java
│ │ │ ├── LanguageRuby.java
│ │ │ ├── LanguageCsharp.java
│ │ │ ├── LanguagePython.java
│ │ │ ├── LanguagePHP.java
│ │ │ ├── c
│ │ │ │ └── CLanguage.java
│ │ │ └── LanguageCFamily.java
│ │ │ └── view
│ │ │ ├── autocomplete
│ │ │ ├── ListItem.java
│ │ │ └── Edit.java
│ │ │ ├── ColorSchemeDark.java
│ │ │ ├── ColorSchemeLight.java
│ │ │ ├── KeysInterpreter.java
│ │ │ ├── SignatureHelpPanel.java
│ │ │ ├── ColorScheme.java
│ │ │ └── ClipboardPanel.java
│ │ └── res
│ │ ├── values-zh
│ │ └── strings.xml
│ │ ├── layout
│ │ ├── auto_panel_item.xml
│ │ └── signature_panel.xml
│ │ └── values
│ │ └── strings.xml
├── build.gradle
└── proguard-rules.pro
├── fastlane
└── metadata
│ └── android
│ ├── en-US
│ ├── title.txt
│ ├── short_description.txt
│ ├── changelogs
│ │ ├── 2.txt
│ │ ├── 4.txt
│ │ ├── 8.txt
│ │ ├── 9.txt
│ │ ├── 5.txt
│ │ ├── 10.txt
│ │ ├── 6.txt
│ │ ├── 3.txt
│ │ └── 7.txt
│ ├── images
│ │ ├── icon.png
│ │ └── phoneScreenshots
│ │ │ ├── 1.jpg
│ │ │ ├── 2.jpg
│ │ │ ├── 3.jpg
│ │ │ └── 4.jpg
│ └── full_description.txt
│ └── ru-RU
│ ├── short_description.txt
│ └── full_description.txt
├── .idea
├── .gitignore
├── codeStyles
│ ├── codeStyleConfig.xml
│ └── Project.xml
├── vcs.xml
├── compiler.xml
├── misc.xml
├── deploymentTargetDropDown.xml
├── gradle.xml
└── jarRepositories.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── settings.gradle
├── .github
├── FUNDING.yml
└── workflows
│ └── build-debug.yml
├── gradle.properties
├── README_zh.md
├── README.md
├── gradlew.bat
└── CODE_OF_CONDUCT.md
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/codeeditor/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/codeeditor/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/title.txt:
--------------------------------------------------------------------------------
1 | TermuC
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # 默认忽略的文件
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | A simple C/C++ IDE backed on Termux
--------------------------------------------------------------------------------
/app/src/main/assets/cld:
--------------------------------------------------------------------------------
1 | # https://clangd.llvm.org/config
2 | CompileFlags:
3 | Add: [-Wall]
--------------------------------------------------------------------------------
/fastlane/metadata/android/ru-RU/short_description.txt:
--------------------------------------------------------------------------------
1 | Простая IDE для C/C++, работающая на базе Termux.
2 |
--------------------------------------------------------------------------------
/app/src/main/assets/Makefile/termuc.json:
--------------------------------------------------------------------------------
1 | {"buildCmd":"make $o/$e -j8 O=$o","compileCmd":"make $o/$e.o -j8 O=$o"}
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2.txt:
--------------------------------------------------------------------------------
1 | - Full translated
2 | - Fixed bugs when detecting file changes
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/codeeditor/src/main/assets/codicon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/codeeditor/src/main/assets/codicon.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/Clang++/termuc.json:
--------------------------------------------------------------------------------
1 | {"buildCmd":"c++ $d/$f -o $o/$e -lm -Wall","compileCmd":"c++ -c $d/$f -o $o/$e.o -lm -Wall"}
--------------------------------------------------------------------------------
/app/src/main/assets/CMake/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_executable(main main.cpp)
2 | target_link_libraries(main m)
3 | add_compile_options(-g -Wall)
--------------------------------------------------------------------------------
/app/src/main/assets/fmt:
--------------------------------------------------------------------------------
1 | # https://clang.llvm.org/docs/ClangFormatStyleOptions.html
2 | Language: Cpp
3 | BasedOnStyle: LLVM
4 | IndentWidth: 4
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/codeeditor/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/fastlane/metadata/android/en-US/images/icon.png
--------------------------------------------------------------------------------
/app/src/main/assets/CMake/termuc.json:
--------------------------------------------------------------------------------
1 | {"buildCmd":"make -j8","compileCmd":"cmake . -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=$o"}
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/4.txt:
--------------------------------------------------------------------------------
1 | • Introduce a simple wizard for initializing
2 | • Update opening files menu
3 | • Support local snippets
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/8.txt:
--------------------------------------------------------------------------------
1 | • Implement textDocument/signatureHelp of LSP
2 | • Introduce some project templates
3 | • Add 'replace' function
4 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/1.jpg
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/3.jpg
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RainbowC0/TermuC/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/4.jpg
--------------------------------------------------------------------------------
/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/Range.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.util;
2 |
3 | public class Range {
4 | public int stl, stc, enl, enc;
5 | public String msg;
6 | }
7 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 22sp
4 | 4dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 20sp
4 | 3dp
5 |
6 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/common/OnCaretScrollListener.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.common;
2 |
3 | public interface OnCaretScrollListener {
4 | void updateCaret(int caretIndex);
5 | }
6 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/common/OnRowChangedListener.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.common;
2 |
3 | public interface OnRowChangedListener {
4 | void onRowChanged(int newRowIndex);
5 | }
6 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/9.txt:
--------------------------------------------------------------------------------
1 | • Add floating-window UI debugger
2 | • Optimize mouse operations
3 | • Adapt for Termux 0.119.0 version
4 | • Fix bugs when copying large text
5 | • Fix bugs when auto-completing
6 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/common/OnSelectionChangedListener.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.common;
2 |
3 | public interface OnSelectionChangedListener {
4 | void onSelectionChanged(boolean active,int selStart, int selEnd);
5 | }
6 |
--------------------------------------------------------------------------------
/codeeditor/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 删除
4 | 格式化
5 | 文本太长,无法复制
6 |
7 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/5.txt:
--------------------------------------------------------------------------------
1 | • Support breakpoint debugging simply (using GDB commandline interface)
2 | • Add 'Font' option
3 | • Collapse action button 'Run' when editing
4 | • Update line highlighting
5 | • Fix bugs when auto indent
6 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/rbc/termuc/FileItem.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.termuc;
2 |
3 | public class FileItem
4 | {
5 | int icon;
6 | String name;
7 |
8 | public FileItem(int icon, String name) {
9 | this.icon = icon;
10 | this.name = name;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
7 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/common/OnKeyShortcutListener.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.common;
2 |
3 | import android.view.KeyEvent;
4 |
5 | public interface OnKeyShortcutListener {
6 | boolean onKeyShortcut(int keyCode,KeyEvent event);
7 | }
8 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/10.txt:
--------------------------------------------------------------------------------
1 | • Support fast-scrolling
2 | • Support horizontal navigation by SogouInput
3 | • Fix missing "/system/bin/nc" for Android 6/7
4 | • Support rename operation
5 | • Fix automatic capitalization for some input methods
6 |
--------------------------------------------------------------------------------
/app/src/main/assets/Makefile/Makefile:
--------------------------------------------------------------------------------
1 | CFLAGS := -g -Wall
2 | LFLAGS := -lm
3 |
4 | all: main
5 | $(O)/%: $(O)/%.o
6 | $(CXX) $^ -o $@ $(LFLAGS)
7 |
8 | $(O)/%.o: %.cpp
9 | $(CXX) -c $^ -o $@ $(CFLAGS)
10 |
11 | .PHONY: clean
12 | clean:
13 | rm -rf $(O)/*
14 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/edit.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/lang/Formatter.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.lang;
2 | import cn.rbc.codeeditor.util.*;
3 |
4 | public interface Formatter
5 | {
6 | //public int createAutoIndent(CharSequence text);
7 | public void format(Document text, int width);
8 | }
9 |
--------------------------------------------------------------------------------
/.idea/deploymentTargetDropDown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/view/autocomplete/ListItem.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.view.autocomplete;
2 |
3 | import java.util.*;
4 |
5 | public class ListItem {
6 | public String label;
7 | public int kind;
8 | public Deque edits = new ArrayDeque<>();
9 | }
10 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/6.txt:
--------------------------------------------------------------------------------
1 | • Support simple project management
2 | • Add 'Indent with spaces' & 'Tab size' options
3 | • Automatically request 'com.termux.permission.RUN_COMMAND' permission
4 | • Fix bugs when switching auto completion
5 | • Fix bugs when detecting soft keyboard
6 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/common/OnTextChangeListener.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.common;
2 | import cn.rbc.codeeditor.util.*;
3 |
4 | public interface OnTextChangeListener {
5 | //void onBeginBatch();
6 | void onChanged(String c, int start, boolean ins, boolean typ);
7 | //void onEndBatch();
8 | }
9 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/view/autocomplete/Edit.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.view.autocomplete;
2 |
3 | public class Edit
4 | {
5 | public String text;
6 | public int start, len;
7 |
8 | @Override
9 | public String toString() {
10 | return text == null ? "null" : text;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/3.txt:
--------------------------------------------------------------------------------
1 | • Update target API to 30 (Android 10)
2 | • Update color schemas
3 | • Support opening any text files
4 | • Add 'Default font size' and 'Show hidden files' options
5 | • Fix bugs when connecting to language server
6 | • Fix bugs that modifications are lost while rotating or etc
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_play_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/7.txt:
--------------------------------------------------------------------------------
1 | Mostly improvements for tablet & landscape
2 |
3 | • Add icons for completion panel in LSP mode
4 | • Handle delete key
5 | • Handle enter key from keyboard when completion
6 | • Enable drag-selection
7 | • Set maximum width for completion panel
8 | • Fix touch-detecting for yoyos
9 | • Hide status bar when landscape
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/header_item.xml:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
4 | distributionSha256Sum=38f66cd6eef217b4c35855bb11ea4e9fbc53594ccccb5fb82dfd317ef8c2c5a3
5 | networkTimeout=10000
6 | validateDistributionUrl=true
7 | zipStoreBase=GRADLE_USER_HOME
8 | zipStorePath=wrapper/dists
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_chevron_left_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_chevron_right_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/key_panel.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 | -
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | // For china developers
4 | /*maven { url 'https://maven.aliyun.com/repository/google' }
5 | maven { url 'https://maven.aliyun.com/repository/central' }*/
6 | google()
7 | mavenCentral()
8 | gradlePluginPortal()
9 | }
10 | }
11 | rootProject.name='TermuC'
12 | include ':app' //, ':lib-n-ide'
13 | include ':codeeditor'
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_code_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_folder_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_file_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v26/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - @string/light
5 | - @string/dark
6 | - @string/sys
7 |
8 |
9 | - l
10 | - d
11 | - s
12 |
13 | s
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_redo_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_undo_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/lang/DefFormatter.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.lang;
2 | import cn.rbc.codeeditor.util.*;
3 |
4 | public class DefFormatter implements Formatter
5 | {
6 | public static char indentChar='\t';
7 | private static DefFormatter _theOne = null;
8 |
9 | public static DefFormatter getInstance() {
10 | if (_theOne == null) {
11 | _theOne = new DefFormatter();
12 | }
13 | return _theOne;
14 | }
15 | public int createAutoIndent(CharSequence text){
16 | return 1;
17 | }
18 | public void format(Document text, int width){
19 |
20 | }
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/search.xml:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_find_replace_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/ErrSpan.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.util;
2 |
3 | public class ErrSpan extends Range
4 | {
5 | public final static int
6 | ERROR = 0,
7 | WARNING = 1,
8 | INFOR = 2,
9 | HINT = 3;
10 | public int severity = 0;
11 |
12 | @Override
13 | public String toString() {
14 | return new StringBuilder()
15 | .append('(')
16 | .append(stl)
17 | .append(':')
18 | .append(stc)
19 | .append(',')
20 | .append(enl)
21 | .append(':')
22 | .append(enc)
23 | .append(",sev=")
24 | .append(severity)
25 | .append(",msg=")
26 | .append(msg)
27 | .append(')').toString();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/editfrag.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/codeeditor/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | namespace 'cn.rbc.termuc'
5 | compileSdk 34
6 |
7 | defaultConfig {
8 | minSdkVersion 21
9 | targetSdkVersion 30
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 |
14 | buildTypes {
15 | release {
16 | minifyEnabled true
17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | compileOptions {
21 | sourceCompatibility = 1.8
22 | targetCompatibility = 1.8
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(dir: 'libs', include: ['*.jar'])
29 | }
30 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/Pair.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.util;
10 |
11 | public final class Pair {
12 | public int first;
13 | public int second;
14 |
15 | public Pair(int x, int y){
16 | first = x;
17 | second = y;
18 | }
19 |
20 | @Override
21 | public String toString() {
22 | return "("+first+","+second+")";
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/assets/init:
--------------------------------------------------------------------------------
1 | ACT=android.settings;PKG=package:com.termux;PT=~/.termux/termux.properties;echo $STR;termux-setup-storage;read -p "$DOA";am start -a $ACT.action.MANAGE_OVERLAY_PERMISSION -d $PKG > /dev/null;read -p "$IBO";am start -a $ACT.IGNORE_BATTERY_OPTIMIZATION_SETTINGS > /dev/null;read -p "$SBP";am start -a $ACT.APPLICATION_DETAILS_SETTINGS -d $PKG > /dev/null;echo $ALE;if [ -f $PT ];then awk '/^#/{print;next }/^\s*allow-external-apps/{gsub(/allow-external-apps.*/,"allow-external-apps=true");found=1}{print $0}END{if(!found)print "allow-external-apps=true"}' $PT > "$TMPDIR/a.tmp" && mv "$TMPDIR/a.tmp" $PT;else mkdir -p $(dirname $PT);echo 'allow-external-apps=true' > $PT;fi;echo $ICL;pkg i clang -y;apt autoremove --purge;apt clean;echo ok
--------------------------------------------------------------------------------
/app/src/main/res/layout/search_action.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/Flag.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.util;
10 |
11 | public class Flag {
12 | private boolean state = false;
13 |
14 | synchronized public final void set(){
15 | state = true;
16 | }
17 |
18 | synchronized public final void clear(){
19 | state = false;
20 | }
21 |
22 | synchronized public final boolean isSet(){
23 | return state;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/codeeditor/src/main/res/layout/auto_panel_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/ProgressObserver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.util;
10 |
11 | /**
12 | * Can be registered with a {@link ProgressSource} of interest, which will cause
13 | * progress updates to be sent to the ProgressObserver.
14 | */
15 | public interface ProgressObserver {
16 | public void onComplete(int requestCode, Object result);
17 | public void onError(int requestCode, int errorCode, String message);
18 | public void onCancel(int requestCode);
19 | }
20 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/codeeditor/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/ru-RU/full_description.txt:
--------------------------------------------------------------------------------
1 | TermuC — простая IDE для C/C++, работающая на базе мощного Termux.
2 |
3 | Установка
4 |
5 | Чтобы использовать все возможности IDE, выполните инструкции по настройке:
6 |
7 | 1. сначала установите Termux(https://f-droid.org/packages/com.termux);
8 | 2. выполните `pkg install clang' для установки компилятора clang & сервера языка clangd;
9 | 3. см. https://github.com/termux/termux-app/wiki/RUN_COMMAND-Intent#setup-instructions для разрешения вызовов из сторонних приложений;
10 | 4. затем установите TermuC.
11 |
12 | Особенности
13 |
14 | ✅ Подсветка синтаксиса
15 | ✅ Автодополнение
16 | ✅ Подсказки параметров
17 | ✅ Форматирование
18 | ✅ Диагностика
19 | ✅ Флаги компиляции
20 | ✅ Тёмная тема
21 | ✅ Отладка
22 | ✅ Управление проектами
23 |
24 | Для подробностей посетите страницу проекта на GitHub.
25 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
20 |
21 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/Lexer.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.util;
2 | import java.io.*;
3 |
4 | public interface Lexer
5 | {
6 | public final static int EOF = 0,
7 | OPERATOR=1, //运算符
8 | IDENTIFIER=2,//标识符
9 | INTEGER_LITERAL=3, //整数
10 | KEYWORD=4, //关键字
11 | TYPE=18, //类型
12 | FLOATING_POINT_LITERAL=5, //浮点
13 | COMMENT=6, //注释
14 | STRING_LITERAL=7,//字符串
15 | COMMA=8, //逗号
16 | SEMICOLON=9,//分号
17 | RBRACK=10,
18 | LBRACK=11,
19 | LPAREN=12,//左括号
20 | RPAREN=13,//右括号
21 | RBRACE=14, //右大括号
22 | LBRACE=15, //左大括号
23 | DOT=16, //点
24 | CHARACTER_LITERAL=17,//字符
25 | PRETREATMENT_LINE=19, //预处理
26 | WHITE_SPACE=20,//空白符
27 | DEFINE_LINE=21,//define
28 | NEW_LINE=22,
29 | ERROR=23;
30 |
31 | public int yylex() throws IOException;
32 | public int yylength();
33 | public String yytext();
34 | public void yyreset(Reader rd);
35 | }
36 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | TermuC is a simple C/C++ IDE backed on powerful Termux. Install Termux first and install clang in Termux to supply the compiler and language server.
2 |
3 | For more details, please visit the project's Github presence.
4 |
5 | Setup
6 |
7 | To support the full functions as an IDE, please follow the setup instruction.
8 |
9 | 1. Install Termux(https://f-droid.org/packages/com.termux) first.
10 | 2. Run `pkg install clang' to install the clang compiler & clangd language server.
11 | 3. See https://github.com/termux/termux-app/wiki/RUN_COMMAND-Intent#setup-instructions to enable calls from 3rd-party apps.
12 | 4. Then install TermuC.
13 |
14 | Features
15 |
16 | ✅ Highlighting
17 | ✅ Autocompletion
18 | ✅ Signature help
19 | ✅ Formatting
20 | ✅ Diagnose
21 | ✅ Compile flags
22 | ✅ Dark mode
23 | ✅ Debug
24 | ✅ Project management
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/file_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
18 |
19 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | namespace 'cn.rbc.termuc'
5 | compileSdk 34
6 | defaultConfig {
7 | applicationId "cn.rbc.termuc"
8 | minSdkVersion 21
9 | targetSdkVersion 31
10 | versionCode 10
11 | versionName "0.2.1"
12 | }
13 |
14 | buildTypes {
15 | release {
16 | minifyEnabled true
17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | compileOptions {
21 | sourceCompatibility = JavaVersion.VERSION_1_7
22 | targetCompatibility = JavaVersion.VERSION_1_7
23 | }
24 | lintOptions {
25 | checkReleaseBuilds false
26 | abortOnError false
27 | }
28 | }
29 |
30 | dependencies {
31 | api project(':codeeditor')
32 | implementation fileTree(dir: 'libs', include: ['*.jar'])
33 | }
34 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12 | polar: # Replace with a single Polar username
13 | custom: ['https://paypal.me/RainbowC0', 'https://img-blog.csdnimg.cn/9c04559a3e064e8786d8aad9d6dababd.jpg'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
14 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/CharSeqReader.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.util;
2 |
3 | import java.io.*;
4 | import cn.rbc.codeeditor.lang.*;
5 | import android.view.*;
6 | import android.os.*;
7 |
8 | public class CharSeqReader extends Reader {
9 | int offset = 0;
10 | CharSequence src;
11 |
12 | public CharSeqReader(CharSequence src) {
13 | this.src = src;
14 | }
15 |
16 | @Override
17 | public void close() {
18 | src = null;
19 | offset = 0;
20 | }
21 |
22 | @Override
23 | public int read(char[] chars, int i, int i1) throws IOException {
24 | int len = Math.min(src.length() - offset, i1);
25 | for (int n = 0; n < len; n++) {
26 | try {
27 | char c = src.charAt(offset++);
28 | if (c == Language.EOF) len = n;
29 | chars[i++] = c;
30 | } catch (Exception e) {
31 | e.printStackTrace();
32 | }
33 | }
34 | if (len <= 0)
35 | return -1;
36 | return len;
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/header_dropdown_item.xml:
--------------------------------------------------------------------------------
1 |
6 |
14 |
23 |
24 |
--------------------------------------------------------------------------------
/.github/workflows/build-debug.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | workflow_dispatch:
8 |
9 | jobs:
10 | build:
11 | name: Build debug apk
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Cancel previous runs
15 | uses: styfle/cancel-workflow-action@0.5.0
16 | with:
17 | access_token: ${{ github.token }}
18 |
19 | - uses: actions/checkout@v2
20 |
21 | - name: set up JDK 17
22 | uses: actions/setup-java@v5
23 | with:
24 | java-version: '17'
25 | distribution: 'dragonwell'
26 | cache: gradle
27 |
28 | - name: Grant execute permission for gradlew
29 | run: chmod +x gradlew
30 |
31 | - name: Build debug apk
32 | uses: eskatos/gradle-command-action@v2
33 | with:
34 | arguments: assembleDebug
35 |
36 | - name: Upload debug apk
37 | uses: actions/upload-artifact@v4
38 | if: ${{ !github.head_ref }}
39 | with:
40 | name: apk-debug
41 | path: app/build/outputs/apk/debug
42 |
--------------------------------------------------------------------------------
/codeeditor/src/main/res/layout/signature_panel.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
21 |
22 |
28 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/replace.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
21 |
22 |
27 |
28 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=false
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=false
20 | android.nonFinalResIds=false
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/view/ColorSchemeDark.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.view;
2 | import android.graphics.*;
3 | import static cn.rbc.codeeditor.view.ColorScheme.Colorable.*;
4 |
5 | public class ColorSchemeDark extends ColorScheme
6 | {
7 | private static ColorScheme mColorScheme;
8 |
9 | private ColorSchemeDark() {
10 | setColor(FOREGROUND, 0xFFF0F0F0);
11 | setColor(BACKGROUND, 0xFF202020);
12 | setColor(BACKGROUND_PURE, 0xFF000000);
13 | setColor(TYPE, 0xFF99CCEE);
14 | setColor(KEYWORD, 0xFF6AB0E2);
15 | setColor(NOTE, 0xFF8AB0E2);
16 | setColor(OPERATOR, 0xFF8AB0E2);
17 | setColor(SECONDARY, 0xFFAAAAAA);
18 | setColor(COMMENT, 0xFF50BB50);
19 | setColor(STRING, 0xFFFF8E8E);
20 | setColor(NUMBER, 0xFFFF8E8E);
21 | setColor(CARET_DISABLED, 0xFFF0F0F0);
22 | setColor(CARET_BACKGROUND, 0xFF42A5F5);
23 | setColor(NON_PRINTING_GLYPH, 0xFF686868);
24 | setColor(LINE_HIGHLIGHT, 0x1E888888);
25 | setColor(SELECTION_BACKGROUND, 0xFF505050);
26 | }
27 |
28 | public static ColorScheme getInstance() {
29 | if (mColorScheme==null)
30 | mColorScheme = new ColorSchemeDark();
31 | return mColorScheme;
32 | }
33 |
34 | @Override
35 | public boolean isDark() {
36 | return true;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
28 |
--------------------------------------------------------------------------------
/README_zh.md:
--------------------------------------------------------------------------------
1 | # TermuC
2 |
3 | [](https://github.com/RainbowC0/TermuC/releases/) [](https://github.com/RainbowC0/TermuC/blob/master/LICENSE.md) 
4 |
5 | TermuC 是一个简单的 C/C++ IDE,采用 Termux 作为后台。项目基于 [MrIkso/CodeEditor](//github.com/MrIkso/CodeEditor)
6 |
7 | [
](https://f-droid.org/packages/cn.rbc.termuc)
10 |
11 | ## 下载
12 |
13 | - Artfacts in [Github Actions](//github.com/RainbowC0/TermuC/actions)
14 | - [F-Droid](//f-droid.org/packages/cn.rbc.termuc)
15 |
16 | ## 截图
17 |
18 | 
19 |
20 | ## 技术原理
21 |
22 | 本应用利用 `com.termux.RUN_COMMAND` 调用 Termux 执行编译命令,并利用 `netcat` 运行 `clangd` 语言服务器,通过 TCP Socket 建立持续的 I/O 通道,提供代码诊断和补全功能。
23 |
24 | ## 特性
25 |
26 | - [x] 代码高亮
27 | - [x] 自动补全
28 | - [x] 格式化
29 | - [x] 代码诊断
30 | - [x] 编译选项
31 | - [x] 暗主题
32 | - [x] 调试
33 | - [x] 项目管理
34 | - [ ] 工作空间
35 |
36 | ## Wiki
37 |
38 | - [*初始化*(很重要)](//github.com/RainbowC0/TermuC/wiki/Setup)
39 | - [使用方法](//github.com/RainbowC0/TermuC/wiki/Usage)
40 |
--------------------------------------------------------------------------------
/codeeditor/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Delete
4 | Format
5 |
6 | Too long text to copy
7 | \uea93
8 | \uea8c
9 | \ueb5f
10 | \uea88
11 | \ueb5b
12 | \ueb61
13 | \uea8b
14 | \uea95
15 | \ueb62
16 | \ueb66
17 | \ueb60
18 | \ueb5d
19 | \uea91
20 | \uea92
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/new_project.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
18 |
19 |
24 |
25 |
30 |
31 |
36 |
37 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
53 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/TextWarriorException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.util;
10 |
11 | import android.util.Log;
12 |
13 | public class TextWarriorException extends Exception {
14 | private static final boolean NDEBUG = false; // set to true to suppress assertions
15 |
16 | public TextWarriorException(String msg) {
17 | super(msg);
18 | }
19 |
20 | static public void fail(final String details) {
21 | assertVerbose(false, details);
22 | }
23 |
24 | @SuppressWarnings("all") //suppress dead code warning when NDEBUG == true
25 | static public void assertVerbose(boolean condition, final String details) {
26 | if (NDEBUG) {
27 | return;
28 | }
29 |
30 | if (!condition) {
31 | /* For Android, a Context has to be passed into this method
32 | * to display the error message on the device screen */
33 | System.err.print("TextWarrior assertion failed: ");
34 | // System.err.println(details);
35 | Log.i("CodeEditor", details);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
26 |
27 |
35 |
36 |
37 |
38 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/lang/xml/XMLLanguage.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.lang.xml;
2 |
3 | import cn.rbc.codeeditor.lang.Language;
4 |
5 |
6 | /**
7 | * Singleton class containing the symbols and operators of the Javascript language
8 | */
9 | public class XMLLanguage extends Language {
10 |
11 | private static XMLLanguage _theOne;
12 |
13 | public static Language getInstance() {
14 | if (_theOne == null) {
15 | _theOne = new XMLLanguage();
16 | }
17 | return _theOne;
18 | }
19 |
20 | private XMLLanguage() {
21 | }
22 |
23 | /**
24 | * Whether the word after c is a token
25 | */
26 |
27 | public boolean isWordStart2(char c) {
28 | return (c == '.');
29 | }
30 |
31 | public boolean isLineAStart(char c) {
32 | return false;
33 | }
34 |
35 | /**
36 | * Whether c0c1 signifies the start of a multi-line token
37 | */
38 | public boolean isMultilineStartDelimiter(char c0, char c1, char c2, char c3) {
39 | return (c0 == '<' && c1 == '!' && c2 == '-' && c3 == '-');
40 | }
41 |
42 | /**
43 | * Whether c0c1 signifies the end of a multi-line token
44 | */
45 | public boolean isMultilineEndDelimiter(char c0, char c1, char c2) {
46 | return (c0 == '-' && c1 == '-' && c2 == '>');
47 | }
48 | public boolean isMultilineStartDelimiter(char c0, char c1) {
49 | return (c0 == '<' && c1 == '!');
50 | }
51 |
52 | /**
53 | * Whether c0c1 signifies the end of a multi-line token
54 | */
55 | public boolean isMultilineEndDelimiter(char c0, char c1) {
56 | return (c0 == '-' && c1 == '>');
57 | }
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TermuC
2 |
3 | [](https://github.com/RainbowC0/TermuC/releases/) [](https://github.com/RainbowC0/TermuC/blob/master/LICENSE.md) 
4 |
5 | [中文 README](./README_zh.md)
6 |
7 | TermuC is a simple C/C++ IDE backed on Termux. Based on [MrIkso/CodeEditor](//github.com/MrIkso/CodeEditor)
8 |
9 | [
](https://f-droid.org/packages/cn.rbc.termuc)
12 |
13 | ## Download
14 |
15 | - Artifacts in [Github Actions](//github.com/RainbowC0/TermuC/actions)
16 | - [F-Droid](//f-droid.org/packages/cn.rbc.termuc)
17 |
18 | ## Screenshot
19 |
20 | 
21 |
22 | ## Technology
23 |
24 | This app uses `com.termux.RUN_COMMAND` to call Termux to run command, and run `clangd` language server with `netcat`, which builds an insistent I/O channel, offering functions as diagnosing and compilation.
25 |
26 | ## Features
27 |
28 | - [x] Highlighting
29 | - [x] Autocompletion
30 | - [x] Formatting
31 | - [x] Diagnosing
32 | - [x] Compile flags
33 | - [x] Dark mode
34 | - [x] Debugging
35 | - [x] Project management
36 | - [ ] Workspace
37 |
38 | ## Wiki
39 |
40 | - [*Setup* (Critical)](//github.com/RainbowC0/TermuC/wiki/Setup)
41 | - [Usage](//github.com/RainbowC0/TermuC/wiki/Usage)
42 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/lang/LanguageJava.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.lang;
10 |
11 | /**
12 | * Singleton class containing the symbols and operators of the Java language
13 | */
14 | public class LanguageJava extends Language{
15 | private static Language _theOne = null;
16 |
17 | private final static String[] keywords = {
18 | "void", "boolean", "byte", "char", "short", "int", "long", "float", "double", "strictfp",
19 | "import", "package", "new", "class", "interface", "extends", "implements", "enum",
20 | "public", "private", "protected", "static", "abstract", "final", "native", "volatile",
21 | "assert", "try", "throw", "throws", "catch", "finally", "instanceof", "super", "this",
22 | "if", "else", "for", "do", "while", "switch", "case", "default",
23 | "continue", "break", "return", "synchronized", "transient",
24 | "true", "false", "null", "import", "package"
25 | };
26 |
27 |
28 | public static Language getInstance(){
29 | if(_theOne == null){
30 | _theOne = new LanguageJava();
31 | }
32 | return _theOne;
33 | }
34 |
35 | private LanguageJava(){
36 | setKeywords(keywords);
37 | }
38 |
39 | /**
40 | * Java has no preprocessors. Override base class implementation
41 | */
42 | public boolean isLineAStart(char c){
43 | return false;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
16 |
17 |
28 |
29 |
37 |
38 |
42 |
43 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/lang/LanguageJavascript.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.lang;
10 |
11 | /**
12 | * Singleton class containing the symbols and operators of the Javascript language
13 | */
14 | public class LanguageJavascript extends LanguageCFamily {
15 | private static LanguageCFamily _theOne = null;
16 |
17 | private final static String[] keywords = {
18 | "abstract", "boolean", "break", "byte", "case", "catch", "char",
19 | "class", "const", "continue", "debugger", "default", "delete", "do",
20 | "double", "else", "enum", "export", "extends", "false", "final",
21 | "finally", "float", "for", "function", "goto", "if", "implements",
22 | "import", "in", "instanceof", "int", "interface", "long", "native",
23 | "new", "null", "package", "private", "protected", "public", "return",
24 | "short", "static", "super", "switch", "synchronized", "this", "throw",
25 | "throws", "transient", "true", "try", "typeof", "var", "void",
26 | "volatile", "while", "with"
27 | };
28 |
29 | public static LanguageCFamily getCharacterEncodings(){
30 | if(_theOne == null){
31 | _theOne = new LanguageJavascript();
32 | }
33 | return _theOne;
34 | }
35 |
36 | private LanguageJavascript(){
37 | super.registerKeywords(keywords);
38 | }
39 |
40 | public boolean isLineAStart(char c){
41 | return false;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/ProgressSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.util;
10 |
11 | /**
12 | * Represents tasks that carry out long computations
13 | */
14 | public interface ProgressSource {
15 | /** Minimum progress value */
16 | public abstract int getMin();
17 | /** Maximum progress value */
18 | public abstract int getMax();
19 | /** Current progress value */
20 | public abstract int getCurrent();
21 |
22 | /** Whether computation is done */
23 | public abstract boolean isDone();
24 | /** Aborts computation */
25 | public abstract void forceStop();
26 | /** Registers observers that will be informed of changes to the progress state */
27 | public abstract void registerObserver(ProgressObserver obsv);
28 | /** Removes all attached observers */
29 | public abstract void removeObservers();
30 |
31 | /* Nature of computation tasks */
32 | static final public int NONE = 0;
33 | static final public int READ = 1;
34 | static final public int WRITE = 2;
35 | static final public int FIND = 4;
36 | static final public int FIND_BACKWARDS = 8;
37 | static final public int REPLACE_ALL = 16;
38 | static final public int ANALYZE_TEXT = 32;
39 |
40 | /* Error codes */
41 | static final public int ERROR_UNKNOWN = 0;
42 | static final public int ERROR_OUT_OF_MEMORY = 1;
43 | static final public int ERROR_INDEX_OUT_OF_RANGE = 2;
44 | }
45 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
23 |
24 |
32 |
33 |
38 |
39 |
43 |
44 |
45 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/lang/LanguageObjectiveC.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.lang;
10 |
11 | /**
12 | * Singleton class containing the symbols and operators of the Objective-C language
13 | */
14 | public class LanguageObjectiveC extends LanguageCFamily{
15 | private static LanguageCFamily _theOne = null;
16 |
17 | private final static String[] keywords = {
18 | "char", "double", "float", "int", "long", "short", "void",
19 | "auto", "const", "extern", "register", "static", "volatile",
20 | "signed", "unsigned", "sizeof", "typedef",
21 | "enum", "struct", "union",
22 | "break", "case", "continue", "default", "do", "else", "for",
23 | "goto", "if", "return", "switch", "while",
24 | "@class", "@implementation", "@interface", "@protocol", "@property",
25 | "@private", "@protected", "@public", "@optional", "@required",
26 | "@defs", "@dynamic", "@encode", "@synchronized", "@selector", "@synthesize",
27 | "@try", "@catch", "@throw", "@finally", "@end",
28 | "id", "self", "super", "nil", "Nil", "NULL", "SEL", "BOOL", "YES", "NO",
29 | "in", "out", "inout", "bycopy", "byref", "oneway",
30 | "getter", "setter", "readwrite", "readonly", "assign", "retain", "copy", "nonatomic"
31 | };
32 |
33 | public static LanguageCFamily getCharacterEncodings(){
34 | if(_theOne == null){
35 | _theOne = new LanguageObjectiveC();
36 | }
37 | return _theOne;
38 | }
39 |
40 | private LanguageObjectiveC(){
41 | super.registerKeywords(keywords);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/var_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
24 |
25 |
31 |
32 |
38 |
39 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/lang/LanguageNonProg.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.lang;
10 | import cn.rbc.codeeditor.util.*;
11 | import java.io.*;
12 |
13 | /**
14 | * Singleton class that represents a non-programming language without keywords,
15 | * operators etc.
16 | */
17 | public class LanguageNonProg extends Language {
18 | private static Language _theOne = null;
19 |
20 | private final static String[] keywords = {};
21 |
22 | private final static char[] operators = {};
23 |
24 |
25 | public static Language getInstance(){
26 | if(_theOne == null){
27 | _theOne = new LanguageNonProg();
28 | }
29 | return _theOne;
30 | }
31 |
32 | private LanguageNonProg(){
33 | super.setKeywords(keywords);
34 | super.setOperators(operators);
35 | }
36 |
37 | @Override
38 | public boolean isProgLang(){
39 | return false;
40 | }
41 |
42 | @Override
43 | public boolean isEscapeChar(char c){
44 | return false;
45 | }
46 |
47 | @Override
48 | public boolean isDelimiterA(char c){
49 | return false;
50 | }
51 |
52 | @Override
53 | public boolean isDelimiterB(char c){
54 | return false;
55 | }
56 |
57 | @Override
58 | public boolean isLineAStart(char c){
59 | return false;
60 | }
61 |
62 | @Override
63 | public boolean isLineStart(char c0, char c1){
64 | return false;
65 | }
66 |
67 | @Override
68 | public boolean isMultilineStartDelimiter(char c0, char c1){
69 | return false;
70 | }
71 |
72 | @Override
73 | public boolean isMultilineEndDelimiter(char c0, char c1){
74 | return false;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/debug_controller.xml:
--------------------------------------------------------------------------------
1 |
7 |
14 |
21 |
28 |
35 |
42 |
47 |
48 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/lang/LanguageRuby.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.lang;
10 |
11 | /**
12 | * Singleton class containing the symbols and operators of the Ruby language
13 | */
14 | public class LanguageRuby extends LanguageCFamily {
15 | private static LanguageCFamily _theOne = null;
16 |
17 | private final static String[] keywords = {
18 | "alias", "and", "BEGIN", "begin", "break", "case", "catch", "class", "def",
19 | "defined?", "do", "else", "elsif", "END", "end", "ensure", "false",
20 | "for", "if", "in", "module", "next", "nil", "not", "or", "public",
21 | "private", "protected", "raise", "redo", "rescue", "retry", "return", "self",
22 | "super", "then", "throw", "true", "undef", "unless", "until", "when", "while",
23 | "yield", "self", "nil", "true", "false", "TRUE", "FALSE", "NIL"
24 | };
25 |
26 |
27 | @Override
28 | public boolean isWordStart(char c){
29 | return (c == '$');
30 | }
31 |
32 | @Override
33 | public boolean isLineAStart(char c){
34 | return false;
35 | }
36 |
37 | @Override
38 | public boolean isLineBStart(char c){
39 | return (c == '#');
40 | }
41 |
42 | @Override
43 | public boolean isLineStart(char c0, char c1){
44 | return false;
45 | }
46 |
47 | @Override
48 | public boolean isMultilineStartDelimiter(char c0, char c1){
49 | return false;
50 | }
51 |
52 | public static LanguageCFamily getCharacterEncodings(){
53 | if(_theOne == null){
54 | _theOne = new LanguageRuby();
55 | }
56 | return _theOne;
57 | }
58 |
59 | private LanguageRuby(){
60 | super.registerKeywords(keywords);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
40 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/lang/LanguageCsharp.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.lang;
10 |
11 | /**
12 | * Singleton class containing the symbols and operators of the C# language
13 | */
14 | public class LanguageCsharp extends LanguageCFamily {
15 | private static LanguageCFamily _theOne = null;
16 |
17 | private final static String[] keywords = {
18 | "abstract", "as", "base", "bool", "break", "byte", "case", "catch",
19 | "char", "checked", "class", "const", "continue", "decimal", "default",
20 | "delegate", "do", "double", "else", "enum", "event", "explicit",
21 | "extern", "false", "finally", "fixed", "float", "for", "foreach",
22 | "goto", "if", "implicit", "in", "int", "interface", "internal", "is",
23 | "lock", "long", "namespace", "new", "null", "object", "operator",
24 | "out", "override", "params", "private", "protected", "public",
25 | "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof",
26 | "stackalloc", "static", "string", "struct", "switch", "this", "throw",
27 | "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe",
28 | "ushort", "using", "virtual", "void", "volatile", "while",
29 | "dynamic", "get", "set", "add", "remove", "global", "value", "var",
30 | "yield", "alias", "partial",
31 | "from", "where", "join", "on", "equals", "into", "let", "orderby",
32 | "ascending", "descending", "select", "group", "by"
33 | };
34 |
35 | public static LanguageCFamily getCharacterEncodings(){
36 | if(_theOne == null){
37 | _theOne = new LanguageCsharp();
38 | }
39 | return _theOne;
40 | }
41 |
42 | private LanguageCsharp(){
43 | super.registerKeywords(keywords);
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/lang/LanguagePython.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.lang;
10 |
11 | /**
12 | * Singleton class containing the symbols and operators of the Python language
13 | */
14 | public class LanguagePython extends LanguageCFamily{
15 | private static LanguageCFamily _theOne = null;
16 |
17 | private final static String[] keywords = {
18 | "and", "assert", "break", "class", "continue", "def", "del",
19 | "elif", "else", "except", "exec", "finally", "for", "from",
20 | "global", "if", "import", "in", "is", "lambda", "not", "or",
21 | "pass", "print", "raise", "return", "try", "while", "with",
22 | "yield", "True", "False", "None"
23 | };
24 |
25 | private final static char[] operators = {
26 | '(', ')', '{', '}', '.', ',', ';', '=', '+', '-',
27 | '/', '*', '&', '!', '|', ':', '[', ']', '<', '>',
28 | '~', '%', '^'
29 | }; // no ternary operator ? :
30 |
31 |
32 | @Override
33 | public boolean isWordStart(char c){
34 | return (c == '@');
35 | }
36 |
37 | @Override
38 | public boolean isLineAStart(char c){
39 | return false;
40 | }
41 |
42 | @Override
43 | public boolean isLineBStart(char c){
44 | return (c == '#');
45 | }
46 |
47 | @Override
48 | public boolean isLineStart(char c0, char c1){
49 | return false;
50 | }
51 |
52 | @Override
53 | public boolean isMultilineStartDelimiter(char c0, char c1){
54 | return false;
55 | }
56 |
57 | public static LanguageCFamily getCharacterEncodings(){
58 | if(_theOne == null){
59 | _theOne = new LanguagePython();
60 | }
61 | return _theOne;
62 | }
63 |
64 | private LanguagePython(){
65 | super.registerKeywords(keywords);
66 | super.replaceOperators(operators);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
14 |
15 |
16 |
17 |
20 |
21 |
32 |
33 |
36 |
37 |
42 |
46 |
47 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/lang/LanguagePHP.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.lang;
10 |
11 | /**
12 | * Singleton class containing the symbols and operators of the PHP language
13 | */
14 | public class LanguagePHP extends LanguageCFamily {
15 | private static LanguageCFamily _theOne = null;
16 |
17 | private final static String[] keywords = {
18 | "abstract", "and", "array", "as", "break", "case", "catch", "class",
19 | "clone", "const", "continue", "declare", "default", "do", "else",
20 | "elseif", "enddeclare", "endfor", "endforeach", "endif", "endswitch",
21 | "endwhile", "extends", "final", "for", "foreach", "function", "global",
22 | "goto", "if", "implements", "interface", "instanceof", "namespace",
23 | "new", "or", "private", "protected", "public", "static", "switch",
24 | "throw", "try", "use", "var", "while", "xor",
25 | "die", "echo", "empty", "exit", "eval", "include", "include_once",
26 | "isset", "list", "require", "require_once", "return", "print", "unset",
27 | "self", "static", "parent", "true", "TRUE", "false", "FALSE", "null", "NULL"
28 | };
29 |
30 | private final static char[] operators = {
31 | '(', ')', '{', '}', '.', ',', ';', '=', '+', '-',
32 | '/', '*', '&', '!', '|', ':', '[', ']', '<', '>',
33 | '?', '~', '%', '^', '`', '@'
34 | };
35 |
36 |
37 | public static LanguageCFamily getCharacterEncodings(){
38 | if(_theOne == null){
39 | _theOne = new LanguagePHP();
40 | }
41 | return _theOne;
42 | }
43 |
44 | private LanguagePHP(){
45 | super.registerKeywords(keywords);
46 | super.replaceOperators(operators);
47 | }
48 |
49 | @Override
50 | public boolean isLineAStart(char c){
51 | return false;
52 | }
53 |
54 | @Override
55 | public boolean isWordStart(char c){
56 | return (c == '$');
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/HelperUtils.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.util;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Canvas;
7 | import android.graphics.drawable.Drawable;
8 | import android.util.TypedValue;
9 |
10 | import android.widget.*;
11 | import android.annotation.*;
12 |
13 | public class HelperUtils {
14 |
15 | private static Toast _t;
16 |
17 | public static float getDpi(Context context) {
18 | return context.getResources().getDisplayMetrics().density;
19 | }
20 |
21 | // create bitmap from vector drawable
22 | public static Bitmap getBitmap(Context context, int res) {
23 | Bitmap bitmap = null;
24 | /* ContextCompat.getDrawable */
25 | Drawable vectorDrawable = context.getDrawable(res);
26 | if (vectorDrawable != null) {
27 | vectorDrawable.setAlpha(210);
28 | //vectorDrawable.setTint(fetchAccentColor(context));
29 | bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(), vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
30 | Canvas canvas = new Canvas(bitmap);
31 | vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
32 | vectorDrawable.draw(canvas);
33 | return bitmap;
34 | }
35 | return bitmap;
36 | }
37 |
38 | public static void show(Toast t) {
39 | if (_t != null)
40 | _t.cancel();
41 | _t = t;
42 | if (t != null)
43 | t.show();
44 | }
45 | /*
46 | public static int codePointAt(CharSequence seq, int pos, int limit) {
47 | // 1. 参数校验
48 | if (pos < 0 || pos >= limit || limit > seq.length()) {
49 | throw new IndexOutOfBoundsException(
50 | "pos=" + pos + ", limit=" + limit + ", length=" + seq.length()
51 | );
52 | }
53 |
54 | // 2. 获取当前字符
55 | char high = seq.charAt(pos);
56 |
57 | // 3. 检查是否为高代理项(High Surrogate)
58 | if (Character.isHighSurrogate(high)) {
59 | // 检查下一个字符是否在有效范围内
60 | if (pos + 1 < limit) {
61 | char low = seq.charAt(pos + 1);
62 | if (Character.isLowSurrogate(low)) {
63 | // 4. 合法代理对:返回组合后的代码点
64 | return Character.toCodePoint(high, low);
65 | }
66 | }
67 | }
68 |
69 | // 5. 单字符或无效代理:返回原始值
70 | return high;
71 | }*/
72 | }
73 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/view/ColorSchemeLight.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 |
10 | package cn.rbc.codeeditor.view;
11 |
12 |
13 | /**
14 | * Off-black on off-white background color scheme
15 | */
16 | public class ColorSchemeLight extends ColorScheme {
17 |
18 | private static ColorScheme mColorScheme;
19 |
20 | private ColorSchemeLight(){
21 | //文字
22 | setColor(Colorable.FOREGROUND, OFF_BLACK);
23 | //背景
24 | setColor(Colorable.BACKGROUND, OFF_WHITE);
25 | setColor(Colorable.BACKGROUND_PURE, 0xFFFFFFFF);
26 | //选取文字
27 | setColor(Colorable.SELECTION_FOREGROUND, OFF_WHITE);
28 | //选取背景
29 | setColor(Colorable.SELECTION_BACKGROUND, 0xFF999999);
30 | //关键字
31 | setColor(Colorable.KEYWORD, BLUE_DARK);
32 | //函数名
33 | //setColor(Colorable.LITERAL, BLUE_LIGHT);
34 | //字符串、数字
35 | setColor(Colorable.STRING, 0xFFAA2200);
36 | setColor(Colorable.NUMBER, 0xFFAA2200);
37 | //类型
38 | setColor(Colorable.TYPE, BLUE_LIGHT); //0xFF2A40FF);
39 | //操作符
40 | setColor(Colorable.OPERATOR, 0xFF007C1F);
41 | //标点
42 | setColor(Colorable.NOTE, 0xFF0096FF);
43 | //宏
44 | setColor(Colorable.SECONDARY, GREY);
45 | //光标
46 | setColor(Colorable.CARET_DISABLED, 0xFF000000);
47 | //yoyo?
48 | setColor(Colorable.CARET_FOREGROUND, OFF_WHITE);
49 | //yoyo背景
50 | setColor(Colorable.CARET_BACKGROUND, 0xFF29B6F6);
51 | //当前行
52 | setColor(Colorable.LINE_HIGHLIGHT, 0x1E888888);
53 |
54 | //注释
55 | setColor(Colorable.COMMENT, GREEN_LIGHT);
56 | /*
57 | setColor(Colorable.FOREGROUND, OFF_BLACK);
58 | setColor(Colorable.BACKGROUND, OFF_WHITE);
59 | setColor(Colorable.SELECTION_FOREGROUND, OFF_WHITE);
60 | setColor(Colorable.CARET_FOREGROUND, OFF_WHITE);*/
61 | }
62 |
63 | private static final int OFF_WHITE = 0xFFF0F0ED;
64 | private static final int OFF_BLACK = 0xFF333333;
65 |
66 | private static final int GREY = 0xFF808080;
67 | private static final int GREEN_LIGHT = 0xFF009B00;
68 | //private static final int GREEN_DARK = 0xFF3F7F5F;
69 | private static final int BLUE_LIGHT = 0xFF0F9CFF;
70 | private static final int BLUE_DARK = 0xFF2C82C8;
71 |
72 | public static ColorScheme getInstance() {
73 | if (mColorScheme==null)
74 | mColorScheme = new ColorSchemeLight();
75 | return mColorScheme;
76 | }
77 |
78 | @Override
79 | public boolean isDark() {
80 | return false;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/rbc/termuc/HeaderAdapter.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.termuc;
2 | import android.content.*;
3 | import android.os.*;
4 | import android.view.*;
5 | import android.widget.*;
6 | import java.io.*;
7 | import java.util.*;
8 |
9 | public class HeaderAdapter extends ArrayAdapter
10 | implements Iterable
11 | {
12 | private final static String BITS = "bs";
13 | private ArrayList bs;
14 | private View.OnClickListener mOnCloseListener;
15 |
16 | public HeaderAdapter(Context context, int id) {
17 | super(context, id, android.R.id.text1);
18 | bs = new ArrayList<>();
19 | setDropDownViewResource(R.layout.header_dropdown_item);
20 | }
21 |
22 | @Override
23 | public View getView(int position, View convertView, ViewGroup parent) {
24 | View v = super.getView(position, convertView, parent);
25 | if (v instanceof TextView) {
26 | TextView tv = (TextView)v;
27 | String s = new File(tv.getText().toString()).getName();
28 | tv.setText(getEdit(position)?"*".concat(s):s);
29 | }
30 | return v;
31 | }
32 |
33 | public void setEdit(int idx, boolean b) {
34 | int i = bs.size();
35 | if (i > idx)
36 | bs.set(idx, b);
37 | else {
38 | for (;i < idx;i++) {
39 | bs.add(false);
40 | }
41 | bs.add(true);
42 | }
43 | }
44 |
45 | public boolean getEdit(int idx) {
46 | return idx)bd.getSerializable(BITS);
55 | }
56 |
57 | @Override
58 | public View getDropDownView(int position, View convertView, ViewGroup parent) {
59 | View v = super.getDropDownView(position, convertView, parent);
60 | View btn = v.findViewById(android.R.id.button1);
61 | btn.setTag(position);
62 | btn.setOnClickListener(mOnCloseListener);
63 | return v;
64 | }
65 |
66 | @Override
67 | public void remove(String object) {
68 | final int pos = this.getPosition(object);
69 | if (bs.size() > pos)
70 | bs.remove(pos);
71 | super.remove(object);
72 | }
73 |
74 | public void setOnCloseListener(View.OnClickListener lis) {
75 | mOnCloseListener = lis;
76 | }
77 |
78 | @Override
79 | public Iterator iterator() {
80 | return new Iterator() {
81 | private int curr = 0;
82 | public boolean hasNext() {
83 | return curr < getCount();
84 | }
85 | public String next() {
86 | return getItem(curr++);
87 | }
88 | public void remove() {}
89 | };
90 | }
91 |
92 | @Override
93 | public Spliterator spliterator() {
94 | return null;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/SearchStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.util;
10 |
11 | public interface SearchStrategy {
12 | /**
13 | * Searches for target, starting from start (inclusive),
14 | * and stopping at end (exclusive).
15 | *
16 | * @return charOffset of found string; -1 if not found
17 | */
18 | public int find(Document src, String target, int start, int end,
19 | boolean isCaseSensitive, boolean isWholeWord);
20 |
21 | /**
22 | * Searches for target, starting from start (inclusive),
23 | * wrapping around to the beginning of document and
24 | * stopping at start (exclusive).
25 | *
26 | * @return charOffset of found string; -1 if not found
27 | */
28 | public int wrappedFind(Document src, String target, int start,
29 | boolean isCaseSensitive, boolean isWholeWord);
30 |
31 | /**
32 | * Searches backwards from startCharOffset (inclusive),
33 | * and stopping at end (exclusive).
34 | *
35 | * @return charOffset of found string; -1 if not found
36 | */
37 | public int findBackwards(Document src, String target, int start, int end,
38 | boolean isCaseSensitive, boolean isWholeWord);
39 |
40 | /**
41 | * Searches backwards from start (inclusive), wrapping around to
42 | * the end of document and stopping at start (exclusive).
43 | *
44 | * @return charOffset of found string; -1 if not found
45 | */
46 | public int wrappedFindBackwards(Document src, String target, int start,
47 | boolean isCaseSensitive, boolean isWholeWord);
48 |
49 | /**
50 | * Replace all matches of searchText in src with replacementText.
51 | *
52 | * @param mark Optional. A position in src that can be tracked for changes.
53 | * After replacements are made, the position may be shifted because of
54 | * insertion/deletion of text before it. The new position of mark is
55 | * returned in Pair.second. If mark is an invalid position, Pair.second
56 | * is undefined.
57 | *
58 | * @return Pair.first is the number of replacements made.
59 | * Pair.second is new position of mark after replacements are made.
60 | */
61 | public Pair replaceAll(Document src, String searchText,
62 | String replacementText, int mark,
63 | boolean isCaseSensitive, boolean isWholeWord);
64 |
65 |
66 | /**
67 | * The number of characters that have been examined by the current find
68 | * operation. This method is not synchronized, and the value returned
69 | * may be outdated.
70 | *
71 | * @return The number of characters searched so far
72 | */
73 | public int getProgress();
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/rbc/termuc/FileActivity.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.termuc;
2 | import android.app.*;
3 | import android.content.*;
4 | import android.os.*;
5 | import android.view.*;
6 | import android.widget.*;
7 | import java.io.*;
8 |
9 | public class FileActivity extends Activity
10 | implements ListView.OnItemClickListener, FileFilter
11 | {
12 | private ListView lv;
13 | private FileAdapter adp;
14 | private File pwd;
15 | final static String FN = "n", PD = "p";
16 |
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState) {
19 | Utils.setNightMode(this, Application.theme);
20 | super.onCreate(savedInstanceState);
21 | ActionBar ab = getActionBar();
22 | ab.setHomeButtonEnabled(true);
23 | setTitle(R.string.select_font);
24 | String path = getIntent().getStringExtra(FN);
25 | if (path != null)
26 | pwd = new File(path).getParentFile();
27 | else pwd = Utils.ROOT;
28 | lv = new ListView(this);
29 | lv.setLayoutParams(new ViewGroup.LayoutParams(
30 | ViewGroup.LayoutParams.MATCH_PARENT,
31 | ViewGroup.LayoutParams.MATCH_PARENT
32 | ));
33 | lv.setFastScrollEnabled(true);
34 | lv.setAdapter(adp = new FileAdapter(this, pwd, this));
35 | lv.setOnItemClickListener(this);
36 | setContentView(lv);
37 | }
38 |
39 | @Override
40 | public void onItemClick(AdapterView> av, View v, int i, long n) {
41 | String _it = adp.getItem(i).name;
42 | if ("..".equals(_it))
43 | pwd = pwd.getParentFile();
44 | else {
45 | File f = new File(pwd, _it);
46 | if (f.isDirectory())
47 | pwd = f;
48 | else {
49 | Intent it = getIntent();
50 | it.putExtra(FN, f.getAbsolutePath());
51 | setResult(RESULT_OK, it);
52 | finish();
53 | return;
54 | }
55 | }
56 | refresh();
57 | }
58 |
59 | @Override
60 | public boolean onOptionsItemSelected(MenuItem item) {
61 | if (item.getItemId() == android.R.id.home) {
62 | finish();
63 | }
64 | return true;
65 | }
66 |
67 | @Override
68 | protected void onSaveInstanceState(Bundle outState) {
69 | super.onSaveInstanceState(outState);
70 | outState.putString(PD, pwd.getAbsolutePath());
71 | }
72 |
73 | @Override
74 | protected void onRestoreInstanceState(Bundle savedInstanceState) {
75 | super.onRestoreInstanceState(savedInstanceState);
76 | pwd = new File(savedInstanceState.getString(PD));
77 | }
78 |
79 | public boolean accept(File p1) {
80 | String p2;
81 | return p1.isDirectory() || ((p2=p1.getName()).endsWith(".ttf") || p2.endsWith(".otf"));
82 | }
83 |
84 | private void refresh() {
85 | getActionBar().setSubtitle(pwd.getAbsolutePath());
86 | adp.setPath(pwd);
87 | adp.notifyDataSetChanged();
88 | }
89 |
90 | @Override
91 | public void onBackPressed() {
92 | if (Utils.ROOT.compareTo(pwd)==0)
93 | super.onBackPressed();
94 | else {
95 | pwd = pwd.getParentFile();
96 | refresh();
97 | }
98 | }
99 |
100 | @Override
101 | protected void onResume() {
102 | super.onResume();
103 | refresh();
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/view/KeysInterpreter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.view;
10 |
11 | import android.view.KeyEvent;
12 |
13 | import cn.rbc.codeeditor.lang.Language;
14 |
15 | public class KeysInterpreter {
16 | public static boolean isSwitchPanel(KeyEvent event) {
17 | return (event.isShiftPressed() &&
18 | (event.getKeyCode() == KeyEvent.KEYCODE_ENTER));
19 | }
20 |
21 | /**
22 | * Maps shortcut keys and Android keycodes to printable characters.
23 | * Note that whitespace is considered printable.
24 | *
25 | * @param event The KeyEvent to interpret
26 | * @return The printable character the event represents,
27 | * or Language.NULL_CHAR if the event does not represent a printable char
28 | */
29 | public static char keyEventToPrintableChar(KeyEvent event) {
30 | char c = Language.NULL_CHAR;
31 |
32 | // convert tab, backspace, newline and space keycodes to standard ASCII values
33 | if (isNewline(event)) {
34 | c = Language.NEWLINE;
35 | } else if (isBackspace(event)) {
36 | c = Language.BACKSPACE;
37 | } else if (isDelete(event)) {
38 | c = Language.DELETE;
39 | // This should be before the check for isSpace() because the
40 | // shortcut for TAB uses the SPACE key.
41 | } else if (isTab(event)) {
42 | c = Language.TAB;
43 | } else if (isSpace(event)) {
44 | c = ' ';
45 | } else if (event.isPrintingKey()) {
46 | c = (char) event.getUnicodeChar(event.getMetaState());
47 | }
48 |
49 | return c;
50 | }
51 |
52 | private static boolean isTab(KeyEvent event) {
53 | return (event.isShiftPressed() &&
54 | (event.getKeyCode() == KeyEvent.KEYCODE_SPACE)) ||
55 | (event.getKeyCode() == KeyEvent.KEYCODE_TAB);
56 | }
57 |
58 | private static boolean isBackspace(KeyEvent event) {
59 | return (event.getKeyCode() == KeyEvent.KEYCODE_DEL);
60 | }
61 |
62 | private static boolean isDelete(KeyEvent event) {
63 | return event.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL;
64 | }
65 |
66 | private static boolean isNewline(KeyEvent event) {
67 | return (event.getKeyCode() == KeyEvent.KEYCODE_ENTER);
68 | }
69 |
70 | private static boolean isSpace(KeyEvent event) {
71 | return (event.getKeyCode() == KeyEvent.KEYCODE_SPACE);
72 | }
73 |
74 | public static boolean isNavigationKey(KeyEvent event) {
75 | int keyCode = event.getKeyCode();
76 | return keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
77 | keyCode == KeyEvent.KEYCODE_DPAD_UP ||
78 | keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
79 | keyCode == KeyEvent.KEYCODE_DPAD_LEFT;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/DLog.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.util;
2 |
3 | import java.util.Arrays;
4 |
5 |
6 | public class DLog {
7 | private static final String TAG = "CodeEditor";
8 | public static boolean DEBUG = true;
9 |
10 | public static int v(String tag, String msg) {
11 | if (!DEBUG)
12 | return 0;
13 | return android.util.Log.v(tag, msg);
14 | }
15 |
16 | public static int v(String tag, String msg, Throwable tr) {
17 | if (!DEBUG)
18 | return 0;
19 | return android.util.Log.v(tag, msg, tr);
20 | }
21 |
22 | public static int d(String msg) {
23 | return d(TAG, msg);
24 | }
25 |
26 | public static int d(String tag, String msg) {
27 | if (!DEBUG)
28 | return 0;
29 | return android.util.Log.d(tag, msg);
30 | }
31 |
32 | public static int d(String tag, String msg, Throwable tr) {
33 | if (!DEBUG)
34 | return 0;
35 | return android.util.Log.d(tag, msg, tr);
36 | }
37 |
38 | public static int d(String format, Object... args) {
39 | return d(TAG, String.format(format, args));
40 | }
41 |
42 | public static int d(Throwable t) {
43 | return d(TAG, t.getMessage(), t);
44 | }
45 |
46 | public static int i(String tag, String msg) {
47 | if (!DEBUG)
48 | return 0;
49 | return android.util.Log.i(tag, msg);
50 | }
51 |
52 | public static int i(String tag, String msg, Throwable tr) {
53 | if (!DEBUG)
54 | return 0;
55 | return android.util.Log.i(tag, msg, tr);
56 | }
57 |
58 | public static int w(String msg) {
59 | return android.util.Log.w(TAG, msg);
60 | }
61 |
62 | public static int w(String tag, String msg) {
63 | return android.util.Log.w(tag, msg);
64 | }
65 |
66 | public static int w(String tag, String msg, Throwable tr) {
67 | return android.util.Log.w(tag, msg, tr);
68 | }
69 |
70 | public static int w(String tag, Throwable tr) {
71 | return android.util.Log.w(tag, tr);
72 | }
73 |
74 | public static int e(String tag, String msg) {
75 | return logError(tag, msg, null);
76 | }
77 |
78 | public static int e(String tag, String msg, Throwable tr) {
79 | return logError(tag, msg, tr);
80 | }
81 |
82 | public static int e(String msg) {
83 | return e(TAG, msg);
84 | }
85 |
86 | public static int e(String msg, Throwable t) {
87 | return e(TAG, msg, t);
88 | }
89 |
90 | public static int e(String format, Object... args) {
91 | return e(TAG, String.format(format, args));
92 | }
93 |
94 | public static int e(Throwable t) {
95 | if (t == null)
96 | return 0;
97 | return logError(TAG, t.getMessage(), t);
98 | }
99 |
100 | private static int logError(String tag, String msg, Throwable t) {
101 | return android.util.Log.e(tag, msg, t);
102 | }
103 |
104 | public static void log(Object... params) {
105 | if (DLog.DEBUG) DLog.d(TAG, "log: " + Arrays.toString(params));
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/lang/c/CLanguage.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.lang.c;
2 |
3 | import cn.rbc.codeeditor.lang.*;
4 | import cn.rbc.codeeditor.util.*;
5 |
6 | public class CLanguage extends Language{
7 | private static Language _theOne = null;
8 |
9 | private final static String[] keywords = {
10 | "auto", "const", "extern", "register", "static", "volatile",
11 | "sizeof", "typedef",
12 | "enum", "struct", "union",
13 | "break", "case", "continue", "default", "do", "else", "for",
14 | "goto", "if", "return", "switch", "while",
15 | /*};
16 | private final static String[] types = {*/
17 | "char", "double", "float", "int", "long", "short", "void",
18 | "signed", "unsigned", "_Bool", "_Complex", "_Imaginary"
19 | };
20 | private final static String[] functions={
21 | "abort","abs","acos","asctime","asin","assert","atan","atan2","atexit","atof","atoi","atol"
22 | ,"bsearch","calloc","ceil","clearerr","clock","cos","cosh","ctime","difftime","div"
23 | ,"exit","exp","fabs","fclose","feof","ferror","fflush","fgetc","fgetpos","fgets","floor"
24 | ,"fmod","fopen","fprintf","fputc","fputs","fread","free","freopen","frexp","fscanf","fseek","fsetpos","ftell","fwrite"
25 | ,"getc","getchar","getenv","gets","gmtime","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","ldexp","ldiv","localtime","log","log10","longjmp"
26 | ,"main","malloc","memchr","memcmp","memcpy","memmove","memset","mktime","modf","perror","pow","printf"
27 | ,"putc","putchar","puts","qsort","raise","rand","realloc","remove","rename","rewind"
28 | ,"scanf","setbuf","setjmp","setvbuf","signal","sin","sinh","sprintf","sqrt","srand","sscanf","strcat","strchr","strcmp","strcoll","strcpy","strcspn","strerror","strftime","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","strtod","strtok","strtol","strtoul","strxfrm","system"
29 | ,"tan","tanh","time","tmpfile","tmpnam","tolower","toupper","ungetc","va_arg","vprintf","vfprintf"
30 | ,"__LINE__","__FILE__","__DATE__","__TIME__","_cplusplus","__STDC__"
31 | };
32 | private final static String[] header={
33 | "math.h","stdio.h","stdlib.h","string.h","time.h","errno.h","ctype.h","local.h"
34 | };
35 | private final static String[] keynames = {
36 | "EOF", "NULL"
37 | };
38 | private final static String[] extraWord = {
39 | "define","include","ifdef","endif","ifndef","error","elif","line","pragma","undef","main"
40 | };
41 | private final static char[] BASIC_C_OPERATORS = {
42 | '(', ')', '{', '}', '.', ',', ';', '=', '+', '-',
43 | '/', '*', '&', '!', '|', ':', '[', ']', '<', '>',
44 | '?', '~', '%', '^'
45 | };
46 | public static Language getInstance(){
47 | if(_theOne == null){
48 | _theOne = new CLanguage();
49 | }
50 | return _theOne;
51 | }
52 |
53 | private CLanguage() {
54 | setKeywords(keywords);
55 | addNames(header);
56 | addNames(functions);
57 | addNames(extraWord);
58 | addKeynames(keynames);
59 | setOperators(BASIC_C_OPERATORS);
60 | }
61 |
62 | @Override
63 | public boolean isProgLang() {
64 | return true;
65 | }
66 |
67 | private CLexer lx = null;
68 |
69 | @Override
70 | public Lexer newLexer(CharSeqReader reader) {
71 | if (lx == null)
72 | lx = new CLexer(reader);
73 | else lx.yyreset(reader);
74 | return lx;
75 | }
76 | }
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/rbc/termuc/Application.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.termuc;
2 | import android.content.*;
3 | import android.graphics.*;
4 | import android.preference.*;
5 | import android.util.*;
6 | import cn.rbc.codeeditor.util.*;
7 | import java.util.*;
8 |
9 | public class Application extends android.app.Application {
10 | final static String
11 | KEY_THEME = "theme",
12 | KEY_PUREMODE = "puremode",
13 | KEY_FONT = "font",
14 | KEY_MYFONT = "myfont",
15 | KEY_WORDWRAP = "wordwrap",
16 | KEY_WHITESPACE = "whitespace",
17 | KEY_TEXTSIZE = "fontsize",
18 | KEY_USESPACE = "usespace",
19 | KEY_TABSIZE = "tabsize",
20 | KEY_SUGGUESTION = "suggestion",
21 | KEY_AUTOCAPS = "autocaps",
22 | KEY_SHOW_HIDDEN = "showhidden",
23 | KEY_CHECKAPP = "checkapp",
24 | KEY_INITAPP = "initapp",
25 | KEY_CFLAGS = "cflags",
26 | KEY_COMPLETION = "completion",
27 | KEY_LSP_HOST = "lsphost",
28 | KEY_LSP_PORT = "lspport";
29 |
30 | public static boolean pure_mode, wordwrap, whitespace, show_hidden, usespace, suggestion, auto_caps;
31 | public static String theme, font, cflags, completion, lsp_host;
32 | public static int lsp_port, textsize, tabsize;
33 |
34 | MainHandler hand;
35 | Lsp lsp;
36 | private Map ls;
37 | private static Application app;
38 |
39 | @Override
40 | public void onCreate() {
41 | super.onCreate();
42 | PreferenceManager.setDefaultValues(this, R.xml.settings, false);
43 | initConfs();
44 | ls = new ArrayMap<>();
45 | app = this;
46 | }
47 |
48 | @Override
49 | public void onTerminate() {
50 | lsp.end();
51 | ls.clear();
52 | super.onTerminate();
53 | app = null;
54 | }
55 |
56 | void store(String key, Document obj) {
57 | ls.put(key, obj);
58 | }
59 |
60 | Document load(String key) {
61 | return ls.remove(key);
62 | }
63 |
64 | public static Application getInstance() {
65 | return app;
66 | }
67 |
68 | private void initConfs() {
69 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
70 | theme = sp.getString(KEY_THEME, getResources().getString(R.string.def_thm));
71 | pure_mode = sp.getBoolean(KEY_PUREMODE, false);
72 | String f = sp.getString(KEY_FONT, "m");
73 | if ("c".equals(f))
74 | f = sp.getString(KEY_MYFONT, "");
75 | font = f;
76 | textsize = Integer.parseInt(sp.getString(KEY_TEXTSIZE, "14"));
77 | wordwrap = sp.getBoolean(KEY_WORDWRAP, true);
78 | whitespace = sp.getBoolean(KEY_WHITESPACE, false);
79 | usespace = sp.getBoolean(KEY_USESPACE, false);
80 | tabsize = Integer.parseInt(sp.getString(KEY_TABSIZE, "4"));
81 | suggestion = sp.getBoolean(KEY_SUGGUESTION, false);
82 | auto_caps = sp.getBoolean(KEY_AUTOCAPS, false);
83 | show_hidden = sp.getBoolean(KEY_SHOW_HIDDEN, true);
84 | cflags = sp.getString(KEY_CFLAGS, "-lm -Wall");
85 | completion = sp.getString(KEY_COMPLETION, "s");
86 | lsp_host = sp.getString(KEY_LSP_HOST, "127.0.0.1");
87 | lsp_port = Integer.parseInt(sp.getString(KEY_LSP_PORT, "48455"));
88 | }
89 |
90 | static Typeface typeface() {
91 | try {
92 | return "n".equals(font) ? Typeface.SANS_SERIF
93 | : "s".equals(font) ? Typeface.SERIF
94 | : "m".equals(font) ? Typeface.MONOSPACE
95 | : Typeface.createFromFile(font);
96 | } catch (RuntimeException re) {
97 | return Typeface.MONOSPACE;
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/rbc/termuc/FileAdapter.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.termuc;
2 | import android.content.*;
3 | import android.view.*;
4 | import android.widget.*;
5 | import java.io.*;
6 | import java.util.*;
7 |
8 | public class FileAdapter extends BaseAdapter implements Comparator, FileFilter
9 | {
10 | private Context mCont;
11 | private static FileItem parent;
12 | private FileItem[] mData;
13 | private boolean mNRoot;
14 | private File mPath;
15 | private LayoutInflater mInflater;
16 | private FileFilter mFilter;
17 |
18 | public FileAdapter(Context context, File path) {
19 | this(context, path, null);
20 | }
21 |
22 | public FileAdapter(Context context, File path, FileFilter filter) {
23 | super();
24 | mCont = context;
25 | mInflater = LayoutInflater.from(context);
26 | mFilter = filter;
27 | setPath(path);
28 | }
29 |
30 | @Override
31 | public long getItemId(int p1) {
32 | return p1;
33 | }
34 |
35 | @Override
36 | public FileItem getItem(int p1) {
37 | if (mNRoot) {
38 | if (p1==0) return parent;
39 | else p1--;
40 | }
41 | return mData[p1];
42 | }
43 |
44 | @Override
45 | public int getCount() {
46 | return mNRoot ? mData.length+1 : mData.length;
47 | }
48 |
49 | @Override
50 | public View getView(int pos, View convert, ViewGroup parent) {
51 | ImageView img;
52 | TextView txv;
53 | ViewHolder vh;
54 | if (convert == null) {
55 | convert = mInflater.inflate(R.layout.file_item, parent, false);
56 | img = convert.findViewById(R.id.file_icon);
57 | txv = convert.findViewById(R.id.file_name);
58 | vh = new ViewHolder();
59 | vh.img = img;
60 | vh.txv = txv;
61 | convert.setTag(vh);
62 | } else {
63 | vh = (ViewHolder)convert.getTag();
64 | img = vh.img;
65 | txv = vh.txv;
66 | }
67 | FileItem fitm = getItem(pos);
68 | img.setImageResource(fitm.icon);
69 | txv.setText(fitm.name);
70 | return convert;
71 | }
72 |
73 | public void setPath(File path) {
74 | mNRoot = !Utils.ROOT.equals(path);
75 | if (parent==null && mNRoot)
76 | parent = new FileItem(R.drawable.ic_folder_24, "..");
77 | mPath = path;
78 | File[] lst = path.listFiles(this);
79 | if (lst==null)
80 | lst = new File[0];
81 | Arrays.sort(lst, this);
82 | mData = new FileItem[lst.length];
83 | for (int i=0,l=lst.length;i
2 |
4 |
6 |
13 |
18 |
19 |
21 |
28 |
35 |
40 |
45 |
50 |
57 |
62 |
67 |
68 |
70 |
75 |
76 |
78 |
82 |
86 |
91 |
92 |
94 |
101 |
107 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/rbc/termuc/Project.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.termuc;
2 | import android.util.*;
3 | import java.io.*;
4 | import java.util.*;
5 |
6 | public class Project
7 | {
8 | private static long lastModified;
9 | private static final String
10 | KEY_BUILDCMD = "buildCmd",
11 | KEY_COMPILE = "compileCmd",
12 | KEY_RUNCMD = "runCmd",
13 | KEY_OUTPUTDIR = "outputDir",
14 | KEY_OPENS = "opens";
15 | public final static String PROJ = "termuc.json";
16 | public static String rootPath, outputDir;
17 | public static String buildCmd, compileCmd, runCmd;
18 |
19 | private static void setDefault() {
20 | buildCmd = "clang $d/$f -o $o/$e -lm -Wall";
21 | compileCmd = "clang -c $d/$f -o $o/$e.o -lm -Wall";
22 | runCmd = "$x/$e";
23 | outputDir = "build";
24 | }
25 |
26 | public static void load(File conf, List opens) throws IOException {
27 | JsonReader p = new JsonReader((new BufferedReader(new FileReader(conf))));
28 | p.beginObject();
29 | setDefault();
30 | while (p.hasNext()) {
31 | switch (p.nextName()) {
32 | case KEY_BUILDCMD: buildCmd = p.nextString(); break;
33 | case KEY_COMPILE: compileCmd = p.nextString(); break;
34 | case KEY_RUNCMD: runCmd = p.nextString(); break;
35 | case KEY_OUTPUTDIR: outputDir = p.nextString(); break;
36 | case KEY_OPENS:
37 | if (opens == null) {
38 | p.skipValue();
39 | break;
40 | }
41 | opens.clear();
42 | p.beginArray();
43 | while (p.hasNext())
44 | opens.add(p.nextString());
45 | p.endArray();
46 | break;
47 | default: p.skipValue();
48 | }
49 | }
50 | p.endObject();
51 | p.close();
52 | rootPath = conf.getParent();
53 | lastModified = conf.lastModified();
54 | }
55 |
56 | public static boolean save(Iterable opens) {
57 | if (rootPath == null)
58 | return false;
59 | File f = new File(rootPath, PROJ);
60 | try {
61 | JsonWriter w = new JsonWriter(new BufferedWriter(new FileWriter(f)));
62 | w.setIndent(" ");
63 | w.beginObject();
64 | w.name(KEY_BUILDCMD);w.value(buildCmd);
65 | w.name(KEY_COMPILE);w.value(compileCmd);
66 | w.name(KEY_RUNCMD);w.value(runCmd);
67 | w.name(KEY_OUTPUTDIR);w.value(outputDir);
68 | w.name(KEY_OPENS);
69 | w.beginArray();
70 | if (opens != null)
71 | for (String s:opens)
72 | w.value(s);
73 | w.endArray();
74 | w.endObject();
75 | w.close();
76 | lastModified = f.lastModified();
77 | return true;
78 | } catch (IOException e) {
79 | return false;
80 | }
81 | }
82 |
83 | public static boolean create(File f) {
84 | rootPath = f.getAbsolutePath();
85 | setDefault();
86 | new File(f, outputDir).mkdirs();
87 | return save(null);
88 | }
89 |
90 | public static void close() {
91 | rootPath = null;
92 | }
93 |
94 | public static long lastModified() {
95 | return lastModified;
96 | }
97 |
98 | public static void reload() throws IOException {
99 | File f = new File(rootPath, PROJ);
100 | if (f.lastModified()>lastModified)
101 | load(f, null);
102 | }
103 | /**
104 | * Local environment variables
105 | * $f file name
106 | * $e file name without suffix
107 | * $d file directory path
108 | * $p project root path (if in project)
109 | * $o outputDir
110 | */
111 | public static StringBuilder buildEnvironment(File file) {
112 | StringBuilder sb = new StringBuilder();
113 | if (rootPath!=null) {
114 | sb.append("p=\"");
115 | sb.append(Utils.escape(rootPath));
116 | sb.append("\";o=\"");
117 | sb.append(Utils.escape(outputDir));
118 | sb.append("\";");
119 | }
120 | if (file!=null) {
121 | sb.append("f=\"");
122 | String name = file.getName();
123 | sb.append(Utils.escape(name));
124 | sb.append("\";e=\"");
125 | // remove suffix
126 | int i = name.lastIndexOf('.');
127 | if (i>=0)
128 | name = name.substring(0, i);
129 | sb.append(Utils.escape(name));
130 | sb.append("\";d=\"");
131 | sb.append(Utils.escape(file.getParent()));
132 | sb.append("\";");
133 | }
134 | return sb;
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/TextBufferCache.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.util;
10 |
11 | /**
12 | * A LRU cache that stores the last seek line and its corresponding index so
13 | * that future lookups can start from the cached position instead of
14 | * the beginning of the file
15 | *
16 | * _cache.Pair.First = line index
17 | * _cache.Pair.Second = character offset of first character in that line
18 | *
19 | * TextBufferCache always has one valid entry (0,0) signifying that in line 0,
20 | * the first character is at offset 0. This is true even for an "empty" file,
21 | * which is not really empty because TextBuffer inserts a EOF character in it.
22 | *
23 | * Therefore, _cache[0] is always occupied by the entry (0,0). It is not affected
24 | * by invalidateCache, cache miss, etc. operations
25 | */
26 | public class TextBufferCache {
27 | private static final int CACHE_SIZE = 4; // minimum = 1
28 | private Pair[] _cache = new Pair[CACHE_SIZE];
29 |
30 | public TextBufferCache() {
31 | _cache[0] = new Pair(0, 0); // invariant lineIndex and charOffset relation
32 | for (int i = 1; i < CACHE_SIZE; ++i)
33 | _cache[i] = new Pair(-1, -1);
34 | // -1 line index is used implicitly in calculations in getNearestMatch
35 | }
36 |
37 | //TODO consider extracting common parts with getNearestCharOffset(int)
38 | public Pair getNearestLine(int lineIndex){
39 | int nearestMatch = 0;
40 | int nearestDistance = Integer.MAX_VALUE;
41 | for(int i = 0; i < CACHE_SIZE; ++i){
42 | int distance = Math.abs(lineIndex - _cache[i].first);
43 | if (distance < nearestDistance){
44 | nearestDistance = distance;
45 | nearestMatch = i;
46 | }
47 | }
48 |
49 | Pair nearestEntry = _cache[nearestMatch];
50 | makeHead(nearestMatch);
51 | return nearestEntry;
52 | }
53 |
54 | public Pair getNearestCharOffset(int charOffset){
55 | int nearestMatch = 0;
56 | int nearestDistance = Integer.MAX_VALUE;
57 | for(int i = 0; i < CACHE_SIZE; ++i){
58 | int distance = Math.abs(charOffset - _cache[i].second);
59 | if (distance < nearestDistance){
60 | nearestDistance = distance;
61 | nearestMatch = i;
62 | }
63 | }
64 |
65 | Pair nearestEntry = _cache[nearestMatch];
66 | makeHead(nearestMatch);
67 | return nearestEntry;
68 | }
69 |
70 | /**
71 | * Place _cache[newHead] at the top of the list
72 | */
73 | private void makeHead(int newHead){
74 | if (newHead == 0)
75 | return;
76 |
77 | Pair temp = _cache[newHead];
78 | for (int i = newHead; i > 1; --i)
79 | _cache[i] = _cache[i-1];
80 | _cache[1] = temp; // _cache[0] is always occupied by (0,0)
81 | }
82 |
83 | public void updateEntry(int lineIndex, int charOffset){
84 | if(lineIndex <= 0)
85 | // lineIndex 0 always has 0 charOffset; ignore. Also ignore negative lineIndex
86 | return;
87 |
88 | if(!replaceEntry(lineIndex, charOffset))
89 | insertEntry(lineIndex, charOffset);
90 | }
91 |
92 | private boolean replaceEntry(int lineIndex, int charOffset){
93 | for (int i = 1; i < CACHE_SIZE; ++i)
94 | if(_cache[i].first == lineIndex){
95 | _cache[i].second = charOffset;
96 | return true;
97 | }
98 | return false;
99 | }
100 |
101 | private void insertEntry(int lineIndex, int charOffset){
102 | makeHead(CACHE_SIZE-1); // rotate right list of entries
103 | // replace head (most recently used entry) with new entry
104 | _cache[1] = new Pair(lineIndex, charOffset);
105 | }
106 |
107 | /**
108 | * Invalidate all cache entries that have char offset >= fromCharOffset
109 | */
110 | final protected void invalidateCache(int fromCharOffset){
111 | for (int i = 1; i < CACHE_SIZE; ++i)
112 | if(_cache[i].second >= fromCharOffset)
113 | _cache[i] = new Pair(-1, -1);
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/GapIntSet.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.util;
2 | import java.util.*;
3 |
4 | public class GapIntSet {
5 | private int[] mData;
6 | private int size, gapSt, gapSz;
7 |
8 | public GapIntSet() {
9 | this(4);
10 | }
11 |
12 | public GapIntSet(int cap) {
13 | if (cap<1)
14 | throw new IllegalArgumentException("Illegal Capacity: "+cap);
15 | mData = new int[cap];
16 | size = 0;
17 | }
18 |
19 | /* copied from ArrayList */
20 | public void ensureCapacity(int cap) {
21 | int[] dt = mData;
22 | int oldCap = dt.length;
23 | if (cap>oldCap) {
24 | int newCap = (oldCap*3)/2+1;
25 | if (newCap < cap)
26 | newCap = cap;
27 | mData = Arrays.copyOf(dt, newCap);
28 | }
29 | }
30 |
31 | /**
32 | * Toggle the int in mData
33 | * @param l the target int
34 | */
35 | public void toggle(int l) {
36 | int idx = set(l);
37 | if (idx >= 0)
38 | remove(idx);
39 | }
40 |
41 | /**
42 | * Try to add an int to mData
43 | * @param l the target int
44 | * @return the index of int l if already exists, or its one's complement after added
45 | */
46 | public int set(int l) {
47 | if (l>=gapSt+gapSz)
48 | l -= gapSz;
49 | else if (l>=gapSt) {
50 | refresh();
51 | gapSz = 0;
52 | }
53 | int idx = Arrays.binarySearch(mData, 0, size, l);
54 | if (idx<0)
55 | add(~idx, l);
56 | return idx;
57 | }
58 |
59 | private void add(int i, int l) {
60 | ensureCapacity(1+size);
61 | System.arraycopy(mData, i, mData, i+1, size - i);
62 | mData[i] = l;
63 | size++;
64 | }
65 |
66 | private void remove(int i) {
67 | int numMoved = size - i - 1;
68 | if (numMoved > 0)
69 | System.arraycopy(mData, i+1, mData, i, numMoved);
70 | size--;
71 | }
72 |
73 | private void refresh() {
74 | int i, j, t;
75 | if (size>0 && gapSz!=0) {
76 | int[] ls = mData;
77 | for (i=size-1; i>=0&&(j=ls[i])>=gapSt; i--)
78 | ls[i] = j+gapSz;
79 | j=i+1;
80 | if (j=0&&ls[i]>=t; i--);
82 | if (j!=(t=i+1)) {
83 | System.arraycopy(mData, j, mData, t, size - j);
84 | size += t-j;
85 | }
86 | }
87 | }
88 | }
89 |
90 | public int[] getData() {
91 | refresh();
92 | gapSz = 0;
93 | return Arrays.copyOf(mData, size);
94 | }
95 |
96 | public void clear() {
97 | size = 0;
98 | }
99 |
100 | public void setData(int[] d) {
101 | size = d.length;
102 | if (d.length==0)
103 | return;
104 | mData = d;
105 | gapSz = 0;
106 | }
107 |
108 | public int size() {
109 | return size;
110 | }
111 |
112 | public int get(int i) {
113 | if (i>=size||i<0)
114 | throw new IndexOutOfBoundsException(String.format(
115 | "Index %d out of bounds for length %d", i, size));
116 | int r = mData[i];
117 | return r>=gapSt?r+gapSz:r;
118 | }
119 |
120 | public void shift(int l, int off) {
121 | int t;
122 | if (off==0||size==0||(t=Math.min(l,l+off))>get(size-1))
123 | return;
124 | if (gapSt<=t&&(gapSz>=0&&l<=gapSt+gapSz)) {
125 | gapSz += off;
126 | } else {
127 | refresh();
128 | int idx = Arrays.binarySearch(mData, 0, size, l-1);
129 | if (idx<0)
130 | idx = (~idx)-1;
131 | if (off>0) {
132 | gapSt = idx<0?0:mData[idx]+1;
133 | gapSz = ++idx==size?off:gapSt-mData[idx];
134 | } else {
135 | gapSt = (++idx==size?l:mData[idx])-1;
136 | l = Arrays.binarySearch(mData, 0, idx, l+off);
137 | if (l<0) l=~l;
138 | gapSz = (l==0?0:mData[l-1]) - gapSt;
139 | }
140 | refresh();
141 | gapSz = off-gapSz;
142 | if (off<0)
143 | gapSt = idx<=0?0:mData[idx-1]+1;
144 | }
145 | }
146 |
147 | public int find(int l) {
148 | if (l>=gapSt+gapSz)
149 | l -= gapSz;
150 | else if (l>gapSt)
151 | l = gapSt;
152 | return Arrays.binarySearch(mData, 0, size, l);
153 | }
154 |
155 | public boolean isInGap(int l) {
156 | return gapSt<=l&&l0) {
164 | sb.append(get(0));
165 | for (int i=1; i _keywords;
27 | protected HashMap _operators;
28 |
29 | private final static char[] basic_c_operators = {
30 | '(', ')', '{', '}', '.', ',', ';', '=', '+', '-',
31 | '/', '*', '&', '!', '|', ':', '[', ']', '<', '>',
32 | '?', '~', '%', '^'
33 | };
34 |
35 | { replaceOperators(basic_c_operators); }
36 |
37 |
38 | protected void registerKeywords(String[] keywords)
39 | {
40 | _keywords = new HashMap(keywords.length);
41 | for (int i = 0; i < keywords.length; ++i)
42 | {
43 | _keywords.put(keywords[i], Tokenizer.KEYWORD);
44 | }
45 | }
46 |
47 | protected void replaceOperators(char[] operators)
48 | {
49 | _operators = new HashMap<>(operators.length);
50 | for (int i = 0; i < operators.length; ++i)
51 | {
52 | _operators.put(operators[i], Tokenizer.OPERATOR);
53 | }
54 | }
55 |
56 | public final boolean isOperator(char c)
57 | {
58 | return _operators.containsKey(c);
59 | }
60 |
61 | public final boolean isKeyword(String s)
62 | {
63 | return _keywords.containsKey(s);
64 | }
65 |
66 | public boolean isWhitespace(char c)
67 | {
68 | return (c == ' ' || c == '\n' || c == '\t' ||
69 | c == '\r' || c == '\f' || c == EOF);
70 | }
71 |
72 | public boolean isSentenceTerminator(char c)
73 | {
74 | return (c == '.');
75 | }
76 |
77 | public boolean isEscapeChar(char c)
78 | {
79 | return (c == '\\');
80 | }
81 |
82 | /**
83 | * Derived classes that do not do represent C-like programming languages
84 | * should return false; otherwise return true
85 | */
86 | public boolean isProgLang()
87 | {
88 | return true;
89 | }
90 |
91 | /**
92 | * Whether the word after c is a token
93 | */
94 | public boolean isWordStart(char c)
95 | {
96 | return false;
97 | }
98 |
99 | /**
100 | * Whether cSc is a token, where S is a sequence of characters that are on the same line
101 | */
102 | public boolean isDelimiterA(char c)
103 | {
104 | return (c == '"');
105 | }
106 |
107 | /**
108 | * Same concept as isDelimiterA(char), but Language and its subclasses can
109 | * specify a second type of symbol to use here
110 | */
111 | public boolean isDelimiterB(char c)
112 | {
113 | return (c == '\'');
114 | }
115 |
116 | /**
117 | * Whether cL is a token, where L is a sequence of characters until the end of the line
118 | */
119 | public boolean isLineAStart(char c)
120 | {
121 | return (c == '#');
122 | }
123 |
124 | /**
125 | * Same concept as isLineAStart(char), but Language and its subclasses can
126 | * specify a second type of symbol to use here
127 | */
128 | public boolean isLineBStart(char c)
129 | {
130 | return false;
131 | }
132 |
133 | /**
134 | * Whether c0c1L is a token, where L is a sequence of characters until the end of the line
135 | */
136 | public boolean isLineStart(char c0, char c1)
137 | {
138 | return (c0 == '/' && c1 == '/');
139 | }
140 |
141 | /**
142 | * Whether c0c1 signifies the start of a multi-line token
143 | */
144 | public boolean isMultilineStartDelimiter(char c0, char c1)
145 | {
146 | return (c0 == '/' && c1 == '*');
147 | }
148 |
149 | /**
150 | * Whether c0c1 signifies the end of a multi-line token
151 | */
152 | public boolean isMultilineEndDelimiter(char c0, char c1)
153 | {
154 | return (c0 == '*' && c1 == '/');
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 设置
4 | 通用
5 | 主题
6 | 亮主题
7 | 暗主题
8 | 跟随系统
9 | 纯色模式
10 | 编辑器
11 | 字体
12 | 无衬线
13 | 衬线
14 | 等宽
15 | 自定义
16 | 自动换行
17 | 显示空白符号
18 | 使用空格进行缩进
19 | 制表符大小(\\t)
20 | 允许键盘建议
21 | 自动输入大写
22 | 编译器
23 | 编译选项
24 | 运行...
25 | 构建
26 | 编译
27 | 运行
28 | 调试
29 | 撤销
30 | 重做
31 | 保存
32 | 查找
33 | 关闭
34 | 项目...
35 | 项目配置
36 | 关闭项目
37 | 未打开文件
38 | 代码分析
39 | 自动补全
40 | 引擎
41 | 语言服务器
42 | 内置代码片段
43 | 无
44 | 服务器地址
45 | 服务器端口
46 | 文件 %s 已被修改,您是否需要重新加载?
47 | 是否删除 %s?
48 | 新建
49 | 文件
50 | 文件夹
51 | 已保存
52 | 正在删除 %s
53 | 已删除
54 | 打开失败!
55 | 浏览文件
56 | 名称(例如 main.cpp)
57 | 项目名称
58 | 打开项目
59 | 打开项目 %s?
60 | 新建文件(夹)
61 | 新建项目
62 | 重命名
63 | 查找…
64 | 下一个
65 | 上一个
66 | 查找结束
67 | 文件浏览器
68 | 显示隐藏文件
69 | 默认字号
70 | 检测&安装 Termux
71 | 已安装
72 | 未安装
73 | 安装 Termux
74 | 未检测到 Termux,是否现在安装?
75 | 不再提醒
76 | 安装途径
77 | 初始化 Termux
78 | 为完成配置,请复制指令并跳转 Termux 粘贴运行。\n运行时需要在所有系统设置页面手动为 Termux 配置权限。
79 | 复制并跳转
80 | STR=设置存储;DOA=设置悬浮窗权限(请按回车);IBO=设置禁用电池优化(请按回车);SBP=设置关联启动与后台弹出权限(请按回车);ALE=设置allow-external-apps;ICL=安装Clang;
87 | 已配置
88 | 申请权限失败
89 | 配置文件解析失败!
90 | 选择字体文件
91 | 模板
92 | 生成 .clangd
93 | 生成 .clang-format
94 | 名称为空!
95 | 替换
96 | 继续
97 | 暂停
98 | 步过
99 | 步入
100 | 步出
101 | 变量
102 | 帧
103 | 控制台
104 | 断点
105 | 信息
106 | GDB命令
107 | 断点于 %s
108 | 无变量信息
109 | 无帧信息
110 |
111 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/key_panel.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
14 |
15 |
19 |
20 |
24 |
25 |
29 |
30 |
34 |
35 |
39 |
40 |
44 |
45 |
49 |
50 |
54 |
55 |
59 |
60 |
64 |
65 |
69 |
70 |
74 |
75 |
79 |
80 |
84 |
85 |
89 |
90 |
94 |
95 |
99 |
100 |
104 |
105 |
109 |
110 |
114 |
115 |
119 |
120 |
124 |
125 |
129 |
130 |
134 |
135 |
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/rbc/termuc/SearchAction.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.termuc;
2 | import android.app.AlertDialog.*;
3 | import android.content.*;
4 | import android.text.*;
5 | import android.view.*;
6 | import android.widget.*;
7 | import cn.rbc.codeeditor.util.*;
8 |
9 | public class SearchAction implements
10 | ActionMode.Callback, TextWatcher, TextView.OnEditorActionListener,
11 | DialogInterface.OnClickListener {
12 | private MainActivity ma;
13 | private EditText e;
14 | private int idx = 0;
15 | private View transV;
16 |
17 | public SearchAction(MainActivity ma) {
18 | this.ma = ma;
19 | }
20 |
21 | public void onDestroyActionMode(ActionMode p1) {
22 | transV = null;
23 | TextEditor te = ma.getEditor();
24 | te.setSelection(te.getCaretPosition());
25 | te.requestFocus();
26 | }
27 |
28 | public boolean onPrepareActionMode(ActionMode p1, Menu p2) {
29 | return false;
30 | }
31 |
32 | public boolean onCreateActionMode(ActionMode p1, Menu p2) {
33 | View v = View.inflate(ma, R.layout.search_action, null);
34 | e = v.findViewById(R.id.search_edit);
35 | TextEditor ed = ma.getEditor();
36 | String st = ed.getSelectedText();
37 | if (!st.isEmpty()) {
38 | e.setText(st);
39 | idx = ed.getSelectionStart();
40 | } else
41 | idx = 0;
42 | e.addTextChangedListener(this);
43 | e.setOnEditorActionListener(this);
44 | p1.setCustomView(v);
45 | ma.getMenuInflater().inflate(R.menu.search, p2);
46 | return true;
47 | }
48 |
49 | public boolean onActionItemClicked(ActionMode p1, MenuItem p2) {
50 | int id = p2.getItemId();
51 | if (id!=R.id.menu_replace)
52 | search(p2.getItemId());
53 | else {
54 | Builder bd = new Builder(ma);
55 | bd.setTitle(R.string.replace);
56 | View v = View.inflate(ma, R.layout.replace, null);
57 | final EditText ed = v.findViewById(R.id.replace_find);
58 | ed.setText(e.getText());
59 | transV = v;
60 | bd.setView(v);
61 | bd.setPositiveButton(android.R.string.ok, this);
62 | bd.setNegativeButton(android.R.string.cancel, null);
63 | bd.create().show();
64 | }
65 | return false;
66 | }
67 |
68 | private void search(int id) {
69 | int i;
70 | CharSequence ed = e.getText();
71 | int len = ed.length();
72 | if (len==0)
73 | return;
74 | TextEditor te = ma.getEditor();
75 | if (id==R.id.menu_last) {
76 | i = rindexDoc(ed, idx-1);
77 | } else {
78 | i = indexDoc(ed, idx+1);
79 | }
80 | if (i<0) {
81 | HelperUtils.show(Toast.makeText(ma, R.string.find_completed, Toast.LENGTH_SHORT));
82 | idx = 0;
83 | te.setSelection(0,0);
84 | } else {
85 | te.setSelection(i, len);
86 | idx = i;
87 | }
88 | return;
89 | }
90 |
91 | public void beforeTextChanged(CharSequence cs, int p1, int p2, int p3) {
92 | }
93 |
94 | public void onTextChanged(CharSequence cs, int p1, int p2, int p3) {
95 | }
96 |
97 | public void afterTextChanged(Editable ed) {
98 | if (ed.length()==0)
99 | return;
100 | int i = indexDoc(ed, idx);
101 | if (i < 0) {
102 | idx = 0;
103 | } else {
104 | idx = i;
105 | ma.getEditor().setSelection(i, ed.length());
106 | }
107 | }
108 |
109 | @Override
110 | public boolean onEditorAction(TextView p1, int p2, KeyEvent p3) {
111 | search(R.id.menu_next);
112 | return true;
113 | }
114 |
115 | private int indexDoc(CharSequence cs, int idx) {
116 | int len = cs.length();
117 | Document doc = ma.getEditor().getText();
118 | int i, ldp = doc.length()-len;
119 | D: for (i=idx; i=0; i--) {
132 | for (int k=0;k sigs;
37 | private int activeSig;
38 |
39 | public SignatureHelpPanel(FreeScrollingTextField editor) {
40 | _editor = editor;
41 | Context ctx = editor.getContext();
42 | LayoutInflater inflater = LayoutInflater.from(ctx);
43 | View root = inflater.inflate(R.layout.signature_panel, null);
44 | _root = root;
45 | View tmp = root.findViewById(R.id.sig_nav);
46 | _navi = tmp;
47 | tmp.measure(View.MeasureSpec.AT_MOST, View.MeasureSpec.AT_MOST);
48 | TextView tv = root.findViewById(R.id.sig_prev);
49 | tv.setOnClickListener(this);
50 | _prev = tv;
51 | tv = root.findViewById(R.id.sig_next);
52 | tv.setOnClickListener(this);
53 | _next = tv;
54 | tv = root.findViewById(R.id.sig_text);
55 | _sigView = tv;
56 |
57 | PopupWindow pw = new PopupWindow(
58 | root,
59 | ViewGroup.LayoutParams.WRAP_CONTENT,
60 | ViewGroup.LayoutParams.WRAP_CONTENT,
61 | false
62 | );
63 | _popupWindow = pw;
64 |
65 | TypedArray array = ctx.getTheme().obtainStyledAttributes(
66 | new int[]{
67 | android.R.attr.colorBackground,
68 | android.R.attr.textColorPrimary
69 | });
70 | int textColor = array.getColor(1, 0xFF00FF);
71 | int backgroundColor = array.getColor(0, 0xFF00FF);
72 | array.recycle();
73 | GradientDrawable g = new GradientDrawable();
74 | g.setColor(backgroundColor);
75 | pw.setBackgroundDrawable(g);
76 | pw.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
77 | pw.setAnimationStyle(0);
78 | pw.setOutsideTouchable(true);
79 | tv.setTextColor(textColor);
80 | g.setStroke(1, textColor);
81 | }
82 |
83 | public void show(List data, int idx) {
84 | if (data == null || data.isEmpty()) {
85 | hide();
86 | return;
87 | }
88 | sigs = data;
89 | select(idx);
90 |
91 | FreeScrollingTextField ed = _editor;
92 | int[] pos = updatePosition(ed);
93 |
94 | View v = _navi;
95 | if (data.size() > 1) {
96 | v.setVisibility(View.VISIBLE);
97 | pos[0] -= v.getWidth();
98 | } else v.setVisibility(View.GONE);
99 |
100 | _popupWindow.showAtLocation(ed, Gravity.NO_GRAVITY, pos[0], pos[1]);
101 | }
102 |
103 | public void hide() {
104 | _popupWindow.dismiss();
105 | }
106 |
107 | public boolean isShowing() {
108 | return _popupWindow.isShowing();
109 | }
110 |
111 | protected static int[] updatePosition(FreeScrollingTextField ed) {
112 | int[] pos = new int[2];
113 | ed.getLocationInWindow(pos);
114 | pos[0] += ed.getCaretX() - ed.getScrollX();
115 | pos[1] += ed.rowHeight() * (1 + ed.getCaretRow()) - ed.getScrollY();
116 | return pos;
117 | }
118 | /*
119 | public void update(int x, int y) {
120 | _popupWindow.update(x, y, -1, -1, true);
121 | }*/
122 |
123 | public void setTextSize(float s) {
124 | _sigView.setTextSize(TypedValue.COMPLEX_UNIT_PX, s);
125 | _prev.setTextSize(TypedValue.COMPLEX_UNIT_PX, s);
126 | _next.setTextSize(TypedValue.COMPLEX_UNIT_PX, s);
127 | _navi.measure(View.MeasureSpec.AT_MOST, View.MeasureSpec.AT_MOST);
128 | }
129 |
130 | private void select(int pos) {
131 | if (pos < 0 || pos > sigs.size()) return;
132 | activeSig = pos;
133 | _sigView.setText(sigs.get(pos));
134 | _prev.setEnabled(pos > 0);
135 | _next.setEnabled(pos+1 < sigs.size());
136 | }
137 |
138 | @Override
139 | public void onClick(View v) {
140 | int i;
141 | if (v.getId() == R.id.sig_prev) i = -1;
142 | else i = 1;
143 | select(activeSig + i);
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/view/ColorScheme.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 |
10 | package cn.rbc.codeeditor.view;
11 |
12 | import cn.rbc.codeeditor.util.Tokenizer;
13 | import cn.rbc.codeeditor.util.TextWarriorException;
14 |
15 | import java.util.HashMap;
16 |
17 | import android.graphics.*;
18 |
19 | public abstract class ColorScheme {
20 | public enum Colorable {
21 | FOREGROUND, BACKGROUND, BACKGROUND_PURE, SELECTION_FOREGROUND,
22 | SELECTION_BACKGROUND, CARET_FOREGROUND, CARET_BACKGROUND, CARET_DISABLED,
23 | LINE_HIGHLIGHT, NON_PRINTING_GLYPH, COMMENT, KEYWORD, NAME, NUMBER, STRING,
24 | SECONDARY, TYPE, NOTE, OPERATOR
25 | }
26 |
27 | protected HashMap _colors = generateDefaultColors();
28 |
29 | public void setColor(Colorable colorable, int color) {
30 | _colors.put(colorable, color);
31 | }
32 |
33 | public int getColor(Colorable colorable) {
34 | Integer color = _colors.get(colorable);
35 | if (color == null) {
36 | TextWarriorException.fail("Color not specified for " + colorable);
37 | return 0;
38 | }
39 | return color;
40 | }
41 |
42 | // Currently, color scheme is tightly coupled with semantics of the token types
43 | public int getTokenColor(int tokenType) {
44 | Colorable element;
45 | switch (tokenType) {
46 | case Tokenizer.NORMAL:
47 | element = Colorable.FOREGROUND;
48 | break;
49 | case Tokenizer.KEYWORD:
50 | element = Colorable.KEYWORD;
51 | break;
52 | case Tokenizer.TYPE:
53 | element = Colorable.TYPE;
54 | break;
55 | case Tokenizer.NAME:
56 | element = Colorable.NAME;
57 | break;
58 | case Tokenizer.DOUBLE_SYMBOL_LINE: //fall-through
59 | case Tokenizer.DOUBLE_SYMBOL_DELIMITED_MULTILINE:
60 | element = Colorable.COMMENT;
61 | break;
62 | case Tokenizer.SINGLE_SYMBOL_DELIMITED_A: //fall-through
63 | case Tokenizer.SINGLE_SYMBOL_DELIMITED_B:
64 | case Tokenizer.KEYNAME:
65 | element = Colorable.STRING;
66 | break;
67 | case Tokenizer.NUMBER:
68 | element = Colorable.NUMBER;
69 | break;
70 | case Tokenizer.NOTE:
71 | element = Colorable.NOTE;
72 | break;
73 | case Tokenizer.OPERATOR:
74 | element = Colorable.OPERATOR;
75 | break;
76 | case Tokenizer.SINGLE_SYMBOL_LINE_A: //fall-through
77 | case Tokenizer.SINGLE_SYMBOL_WORD:
78 | element = Colorable.SECONDARY;
79 | break;
80 | case Tokenizer.SINGLE_SYMBOL_LINE_B: //类型
81 | element = Colorable.NAME;
82 | break;
83 | default:
84 | TextWarriorException.fail("Invalid token type");
85 | element = Colorable.FOREGROUND;
86 | break;
87 | }
88 | return getColor(element);
89 | }
90 |
91 | /**
92 | * Whether this color scheme uses a dark background, like black or dark grey.
93 | */
94 | public abstract boolean isDark();
95 |
96 | private HashMap generateDefaultColors() {
97 | // High-contrast, black-on-white color scheme
98 | HashMap colors = new HashMap(Colorable.values().length);
99 | colors.put(Colorable.FOREGROUND, BLACK);//前景色
100 | colors.put(Colorable.BACKGROUND, WHITE);
101 | colors.put(Colorable.SELECTION_FOREGROUND, WHITE);//选择文本的前景色
102 | colors.put(Colorable.SELECTION_BACKGROUND, 0xFF97C024);//选择文本的背景色
103 | colors.put(Colorable.CARET_FOREGROUND, WHITE);
104 | colors.put(Colorable.CARET_BACKGROUND, BLACK);
105 | colors.put(Colorable.CARET_DISABLED, GREY);
106 | colors.put(Colorable.LINE_HIGHLIGHT, 0x20888888);
107 |
108 | colors.put(Colorable.NON_PRINTING_GLYPH, 0xFFBBBBBB);//行号
109 | colors.put(Colorable.COMMENT, OLIVE_GREEN); //注释
110 | colors.put(Colorable.KEYWORD, BLUE); //关键字
111 | colors.put(Colorable.NAME, GREY); // Eclipse default color
112 | colors.put(Colorable.NUMBER, PINK); // 数字
113 | colors.put(Colorable.STRING, DARK_RED); //字符串
114 | colors.put(Colorable.SECONDARY, 0xff6f008a);//宏定义
115 | return colors;
116 | }
117 |
118 | // In ARGB format: 0xAARRGGBB
119 | private static final int BLACK = 0xFF000000;
120 | private static final int BLUE = 0xFF0000FF;
121 | private static final int DARK_RED = 0xFFA31515;
122 | private static final int PINK = 0xFFD040DD;
123 | private static final int GREY = 0xFF808080;
124 | private static final int OLIVE_GREEN = 0xFF3F7F5F;
125 | private static final int WHITE = 0xFFFFFFE0;
126 | private static final int LIGHT_BLUE2 = 0xFF40B0FF;
127 |
128 | static final int[] DIAG = {Color.RED, Color.MAGENTA, 0xFF00BB00, Color.CYAN};
129 | }
130 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | TermuC.CODE_OF_CONDUCT.md.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/debug_panel.xml:
--------------------------------------------------------------------------------
1 |
5 |
9 |
17 |
21 |
22 |
27 |
31 |
43 |
47 |
55 |
56 |
60 |
64 |
72 |
73 |
78 |
84 |
91 |
92 |
100 |
101 |
105 |
109 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/FindThread.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.util;
10 |
11 | import java.util.Vector;
12 |
13 |
14 | /**
15 | * Worker thread to carry our find and replaceAll operations.
16 | * The find thread should not be reused after it has completed. Create a new one
17 | * for another operation.
18 | */
19 | public class FindThread extends Thread implements ProgressSource {
20 | /**
21 | * Reported progress will be scaled from 0 to MAX_PROGRESS
22 | */
23 | private final static int MAX_PROGRESS = 100;
24 | final private SearchStrategy FINDER = new LinearSearchStrategy();
25 | protected int _requestCode;
26 | protected Document _src;
27 | protected Vector _progressObservers = new Vector();
28 | protected String _searchText;
29 | protected String _replacementText;
30 | protected int _start;
31 | protected boolean _isCaseSensitive;
32 | protected boolean _isWholeWord;
33 | protected boolean _isDone = false;
34 | protected FindResults _results;
35 | private int _docSize = 0; // size, in chars, of the document to search
36 |
37 | private FindThread(int requestCode, Document src, String searchText, int start,
38 | boolean isCaseSensitive, boolean isWholeWord) {
39 | _requestCode = requestCode;
40 | _src = src;
41 | _start = start;
42 | _searchText = searchText;
43 | _isCaseSensitive = isCaseSensitive;
44 | _isWholeWord = isWholeWord;
45 | _docSize = src.length();
46 | }
47 |
48 | private FindThread(int requestCode, Document src, String searchText, String replacementText, int start,
49 | boolean isCaseSensitive, boolean isWholeWord) {
50 | _requestCode = requestCode;
51 | _src = src;
52 | _start = start;
53 | _searchText = searchText;
54 | _replacementText = replacementText;
55 | _isCaseSensitive = isCaseSensitive;
56 | _isWholeWord = isWholeWord;
57 | _docSize = src.length();
58 | }
59 |
60 | static public FindThread createFindThread(Document src, String searchText, int start, boolean isForwardSearch,
61 | boolean isCaseSensitive, boolean isWholeWord) {
62 |
63 | int requestCode = (isForwardSearch) ? ProgressSource.FIND : ProgressSource.FIND_BACKWARDS;
64 |
65 | return new FindThread(requestCode, src, searchText, start, isCaseSensitive, isWholeWord);
66 | }
67 |
68 | static public FindThread createReplaceAllThread(Document src, String searchText, String replacementText, int start,
69 | boolean isCaseSensitive, boolean isWholeWord) {
70 | return new FindThread(ProgressSource.REPLACE_ALL, src, searchText, replacementText, start, isCaseSensitive, isWholeWord);
71 | }
72 |
73 | public void run() {
74 | _isDone = false;
75 | _results = new FindResults(_searchText.length());
76 |
77 | switch (_requestCode) {
78 | case ProgressSource.FIND:
79 | _results.foundOffset = FINDER.wrappedFind(_src, _searchText, _start, _isCaseSensitive, _isWholeWord);
80 | notifyComplete(_results);
81 | break;
82 | case ProgressSource.FIND_BACKWARDS:
83 | _results.foundOffset = FINDER.wrappedFindBackwards(_src, _searchText, _start,
84 | _isCaseSensitive, _isWholeWord);
85 | notifyComplete(_results);
86 | break;
87 | case ProgressSource.REPLACE_ALL:
88 | Pair replaceResult = FINDER.replaceAll(_src, _searchText, _replacementText, _start,
89 | _isCaseSensitive, _isWholeWord);
90 | _results.replacementCount = replaceResult.first;
91 | _results.newStartPosition = replaceResult.second;
92 | notifyComplete(_results);
93 | break;
94 | default:
95 | TextWarriorException.assertVerbose(false, "Invalid request code for FindThread");
96 | break;
97 | }
98 | }
99 |
100 | @Override
101 | public final int getMin() {
102 | return 0;
103 | }
104 |
105 | @Override
106 | public final int getMax() {
107 | return MAX_PROGRESS;
108 | }
109 |
110 | @Override
111 | public final int getCurrent() {
112 | float progressProportion = (_docSize == 0) ? 0.f : (float) FINDER.getProgress() / (float) _docSize;
113 | return (int) (progressProportion * MAX_PROGRESS);
114 | }
115 |
116 | @Override
117 | public final void forceStop() {
118 | //TODO implement
119 | }
120 |
121 | @Override
122 | public final boolean isDone() {
123 | return _isDone;
124 | }
125 |
126 | @Override
127 | synchronized public final void registerObserver(ProgressObserver po) {
128 | _progressObservers.addElement(po);
129 | }
130 |
131 | @Override
132 | synchronized public final void removeObservers() {
133 | _progressObservers.clear();
134 | }
135 |
136 | synchronized protected void notifyComplete(Object result) {
137 | _isDone = true;
138 | for (ProgressObserver po : _progressObservers) {
139 | po.onComplete(_requestCode, result);
140 | }
141 | }
142 |
143 | public final int getRequestCode() {
144 | return _requestCode;
145 | }
146 |
147 | public final FindResults getResults() {
148 | return _results;
149 | }
150 |
151 | public static class FindResults {
152 | public int foundOffset = -1;
153 | public int replacementCount = 0;
154 | public int newStartPosition = 0;
155 | public int searchTextLength = 0; //for convenience
156 |
157 | public FindResults(int searchLength) {
158 | searchTextLength = searchLength;
159 | }
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/rbc/termuc/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.termuc;
2 | import android.content.*;
3 | import android.os.*;
4 | import android.preference.*;
5 | import android.view.*;
6 |
7 | public class SettingsActivity extends PreferenceActivity
8 | implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener
9 | {
10 | private final static String TAG = "SettingsActivity", FT = "f";
11 |
12 | private CheckBoxPreference mPureModePref, mWordWrapPref, mWhitespacePref, mUseSpacePref,
13 | mShowHidden, mSuggestionPref, mAutoCapsPref;
14 | private EditTextPreference mCFlagsPref, mHost, mPort;
15 | private ListPreference mThemePref, mFontPref, mSizePref, mTabSizePref, mEngine;
16 |
17 | private boolean mPure, mWrap, mSpace, mUseSpace, mSuggestion, mAutoCaps;
18 | private String mTheme, mComp, mFont, tpFont;
19 | private int mTabSize;
20 |
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | Utils.setNightMode(this, Application.theme);
24 | super.onCreate(savedInstanceState);
25 | getActionBar().setDisplayHomeAsUpEnabled(true);
26 | addPreferencesFromResource(R.xml.settings);
27 |
28 | mThemePref = (ListPreference)findPreference(Application.KEY_THEME);
29 | mPureModePref = (CheckBoxPreference)findPreference(Application.KEY_PUREMODE);
30 | mFontPref = (ListPreference)findPreference(Application.KEY_FONT);
31 | mFontPref.setOnPreferenceChangeListener(this);
32 | mSizePref = (ListPreference)findPreference(Application.KEY_TEXTSIZE);
33 | mWordWrapPref = (CheckBoxPreference)findPreference(Application.KEY_WORDWRAP);
34 | mWhitespacePref = (CheckBoxPreference)findPreference(Application.KEY_WHITESPACE);
35 | mUseSpacePref = (CheckBoxPreference)findPreference(Application.KEY_USESPACE);
36 | mTabSizePref = (ListPreference)findPreference(Application.KEY_TABSIZE);
37 | mSuggestionPref = (CheckBoxPreference)findPreference(Application.KEY_SUGGUESTION);
38 | mAutoCapsPref = (CheckBoxPreference)findPreference(Application.KEY_AUTOCAPS);
39 | mShowHidden = (CheckBoxPreference)findPreference(Application.KEY_SHOW_HIDDEN);
40 | mCFlagsPref = (EditTextPreference)findPreference(Application.KEY_CFLAGS);
41 | mEngine = (ListPreference)findPreference(Application.KEY_COMPLETION);
42 | mEngine.setOnPreferenceChangeListener(this);
43 | mHost = (EditTextPreference)findPreference(Application.KEY_LSP_HOST);
44 | mPort = (EditTextPreference)findPreference(Application.KEY_LSP_PORT);
45 | findPreference(Application.KEY_CHECKAPP).setOnPreferenceClickListener(this);
46 | findPreference(Application.KEY_INITAPP).setOnPreferenceClickListener(this);
47 | onPreferenceChange(mEngine, mEngine.getValue());
48 |
49 | mTheme = Application.theme;
50 | mPure = Application.pure_mode;
51 | mWrap = Application.wordwrap;
52 | mSpace = Application.whitespace;
53 | mUseSpace = Application.usespace;
54 | mTabSize = Application.tabsize;
55 | mSuggestion = Application.suggestion;
56 | mAutoCaps = Application.auto_caps;
57 | mComp = Application.completion;
58 | mFont = tpFont = Application.font;
59 | }
60 |
61 | @Override
62 | public boolean onOptionsItemSelected(MenuItem item) {
63 | switch (item.getItemId()) {
64 | case android.R.id.home:
65 | onBackPressed();
66 | break;
67 | }
68 | return true;
69 | }
70 |
71 | @Override
72 | public boolean onPreferenceClick(Preference p1) {
73 | if (Application.KEY_CHECKAPP.equals(p1.getKey()))
74 | Utils.testApp(this, true);
75 | else
76 | Utils.initBack(this, true);
77 | return true;
78 | }
79 |
80 | @Override
81 | public boolean onPreferenceChange(Preference p1, Object p2) {
82 | if (p1.compareTo(mEngine)==0) {
83 | boolean enable = "s".equals(p2);
84 | mHost.setEnabled(enable);
85 | mPort.setEnabled(enable);
86 | } else if (p1.compareTo(mFontPref)==0) {
87 | if ("c".equals(p2)) {
88 | Intent it = new Intent(this, FileActivity.class);
89 | it.putExtra(FileActivity.FN,
90 | getPreferenceManager().getSharedPreferences().getString(Application.KEY_MYFONT, null));
91 | startActivityForResult(it, 0);
92 | return false;
93 | }
94 | tpFont = (String)p2;
95 | }
96 | return true;
97 | }
98 |
99 | @Override
100 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
101 | super.onActivityResult(requestCode, resultCode, data);
102 | if (requestCode==0 && resultCode==RESULT_OK) {
103 | SharedPreferences.Editor edt = getPreferenceManager().getSharedPreferences().edit();
104 | edt.putString(Application.KEY_MYFONT, tpFont = data.getStringExtra(FileActivity.FN));
105 | edt.commit();
106 | mFontPref.setValue("c");
107 | }
108 | }
109 |
110 | @Override
111 | public void onBackPressed() {
112 | setResult(mTheme != mThemePref.getValue()
113 | ? RESULT_FIRST_USER :
114 | (mPure == mPureModePref.isChecked()
115 | && mFont == tpFont
116 | && mWrap == mWordWrapPref.isChecked()
117 | && mSpace == mWhitespacePref.isChecked()
118 | && mUseSpace == mUseSpacePref.isChecked()
119 | && mTabSize == Integer.parseInt(mTabSizePref.getValue())
120 | && mSuggestion == mSuggestionPref.isChecked()
121 | && mAutoCaps == mAutoCapsPref.isChecked()
122 | && mComp.equals(mEngine.getValue()))
123 | ? RESULT_CANCELED : RESULT_OK);
124 | super.onBackPressed();
125 | }
126 |
127 | @Override
128 | protected void onSaveInstanceState(Bundle outState) {
129 | super.onSaveInstanceState(outState);
130 | outState.putString(FT, tpFont);
131 | }
132 |
133 | @Override
134 | protected void onRestoreInstanceState(Bundle state) {
135 | super.onRestoreInstanceState(state);
136 | tpFont = state.getString(FT);
137 | }
138 |
139 | @Override
140 | protected void onPause() {
141 | Application.theme = mThemePref.getValue();
142 | Application.pure_mode = mPureModePref.isChecked();
143 | Application.wordwrap = mWordWrapPref.isChecked();
144 | Application.whitespace = mWhitespacePref.isChecked();
145 | Application.usespace = mUseSpacePref.isChecked();
146 | Application.tabsize = Integer.parseInt(mTabSizePref.getValue());
147 | Application.font = tpFont;
148 | Application.textsize = Integer.parseInt(mSizePref.getValue());
149 | Application.suggestion = mSuggestionPref.isChecked();
150 | Application.auto_caps = mAutoCapsPref.isChecked();
151 | Application.show_hidden = mShowHidden.isChecked();
152 | Application.cflags = mCFlagsPref.getText();
153 | Application.completion = mEngine.getValue();
154 | Application.lsp_host = mHost.getText();
155 | Application.lsp_port = Integer.parseInt(mPort.getText());
156 | super.onPause();
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/view/ClipboardPanel.java:
--------------------------------------------------------------------------------
1 | package cn.rbc.codeeditor.view;
2 |
3 | import android.content.*;
4 | import android.content.res.*;
5 | import android.graphics.*;
6 | import android.os.*;
7 | import android.view.*;
8 | import cn.rbc.termuc.*;
9 |
10 | public class ClipboardPanel implements ActionMode.Callback {
11 | protected FreeScrollingTextField _textField;
12 | private Context _context;
13 |
14 | private ActionMode _clipboardActionMode;
15 | private ActionMode.Callback2 _clipboardActionModeCallback2;
16 |
17 | public ClipboardPanel(FreeScrollingTextField textField) {
18 | _textField = textField;
19 | _context = textField.getContext();
20 | }
21 |
22 | public Context getContext() {
23 | return _context;
24 | }
25 |
26 | public void show() {
27 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
28 | initData();
29 | startClipboardActionNew();
30 | } else
31 | startClipboardAction();
32 | }
33 |
34 | public void hide() {
35 | stopClipboardAction();
36 | }
37 |
38 | public void startClipboardAction() {
39 | if (_clipboardActionMode == null)
40 | _textField.startActionMode(this);
41 | }
42 |
43 | @Override
44 | public boolean onCreateActionMode(ActionMode mode, Menu menu) {
45 | _clipboardActionMode = mode;
46 | //mode.setTitle(android.R.string.selectTextMode);
47 | TypedArray array = _context.getTheme().obtainStyledAttributes(
48 | new int[]{
49 | android.R.attr.actionModeSelectAllDrawable,
50 | android.R.attr.actionModeCutDrawable,
51 | android.R.attr.actionModeCopyDrawable,
52 | android.R.attr.actionModePasteDrawable
53 | });
54 | menu.add(0, 0, 0, _context.getString(android.R.string.selectAll))
55 | .setShowAsActionFlags(2)
56 | .setAlphabeticShortcut('a')
57 | .setIcon(array.getDrawable(0));
58 |
59 | menu.add(0, 1, 0, _context.getString(android.R.string.cut))
60 | .setShowAsActionFlags(2)
61 | .setAlphabeticShortcut('x')
62 | .setIcon(array.getDrawable(1));
63 |
64 | menu.add(0, 2, 0, _context.getString(android.R.string.copy))
65 | .setShowAsActionFlags(2)
66 | .setAlphabeticShortcut('c')
67 | .setIcon(array.getDrawable(2));
68 |
69 | menu.add(0, 3, 0, _context.getString(android.R.string.paste))
70 | .setShowAsActionFlags(2)
71 | .setAlphabeticShortcut('v')
72 | .setIcon(array.getDrawable(3));
73 |
74 | menu.add(0, 4, 0, _context.getString(R.string.delete))
75 | .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM)
76 | .setAlphabeticShortcut('d');
77 |
78 | menu.add(0, 5, 0, _context.getString(R.string.format))
79 | .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM)
80 | .setAlphabeticShortcut('f');
81 | array.recycle();
82 | return true;
83 | }
84 |
85 | @Override
86 | public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
87 | return false;
88 | }
89 |
90 | @Override
91 | public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
92 | switch (item.getItemId()) {
93 | case 0:
94 | _textField.selectAll();
95 | break;
96 | case 1:
97 | _textField.cut();
98 | mode.finish();
99 | break;
100 | case 2:
101 | _textField.copy();
102 | mode.finish();
103 | break;
104 | case 3:
105 | _textField.paste();
106 | mode.finish();
107 | break;
108 | case 4:
109 | _textField.delete();
110 | mode.finish();
111 | break;
112 | case 5:
113 | _textField.format();
114 | mode.finish();
115 | }
116 | return false;
117 | }
118 |
119 | @Override
120 | public void onDestroyActionMode(ActionMode p1) {
121 | _textField.selectText(false);
122 | _clipboardActionMode = null;
123 | }
124 |
125 | public void startClipboardActionNew() {
126 | if (_clipboardActionMode == null) {
127 | _textField.startActionMode(_clipboardActionModeCallback2, ActionMode.TYPE_FLOATING);
128 | }
129 | }
130 |
131 | private void initData() {
132 | _clipboardActionModeCallback2 = new ActionMode.Callback2() {
133 | // private Rect caret;
134 | @Override
135 | public boolean onCreateActionMode(ActionMode mode, Menu menu) {
136 | _clipboardActionMode = mode;
137 | FreeScrollingTextField fld = _textField;
138 | boolean isSel = fld.getSelectionStart() != fld.getSelectionEnd();
139 | menu.add(0, 0, 0, _context.getString(android.R.string.selectAll))
140 | .setShowAsActionFlags(2)
141 | .setAlphabeticShortcut('a');
142 | menu.add(0, 1, 0, _context.getString(android.R.string.cut))
143 | .setShowAsActionFlags(2)
144 | .setAlphabeticShortcut('x').setEnabled(isSel);
145 | menu.add(0, 2, 0, _context.getString(android.R.string.copy))
146 | .setShowAsActionFlags(2)
147 | .setAlphabeticShortcut('c').setEnabled(isSel);
148 | menu.add(0, 3, 0, _context.getString(android.R.string.paste))
149 | .setShowAsActionFlags(2)
150 | .setAlphabeticShortcut('v');
151 | menu.add(0, 4, 0, _context.getString(R.string.delete))
152 | .setShowAsActionFlags(2)
153 | .setAlphabeticShortcut('d').setEnabled(isSel);
154 | menu.add(0, 5, 0, _context.getString(R.string.format))
155 | .setShowAsActionFlags(2)
156 | .setAlphabeticShortcut('f');
157 | return true;
158 | }
159 |
160 | @Override
161 | public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
162 | return false;
163 | }
164 |
165 | @Override
166 | public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
167 | return ClipboardPanel.this.onActionItemClicked(mode, item);
168 | }
169 |
170 | @Override
171 | public void onDestroyActionMode(ActionMode p1) {
172 | _textField.selectText(false);
173 | _clipboardActionMode = null;
174 | //caret = null;
175 | }
176 |
177 | @Override
178 | public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
179 | FreeScrollingTextField fld = _textField;
180 | Rect caret = fld.getBoundingBox(fld.getSelectionStart());
181 | int x = fld.getScrollX(), y = fld.getScrollY();
182 | caret.top -= y;
183 | caret.bottom = Math.max(0, caret.bottom-y);
184 | caret.left -= x;
185 | caret.right -= x;
186 | outRect.set(caret);
187 | Menu menu = mode.getMenu();
188 | boolean isSel = fld.getSelectionStart() != fld.getSelectionEnd();
189 | menu.findItem(1).setEnabled(isSel);
190 | menu.findItem(2).setEnabled(isSel);
191 | menu.findItem(4).setEnabled(isSel);
192 | }
193 | };
194 |
195 | }
196 |
197 | public void stopClipboardAction() {
198 | if (_clipboardActionMode != null) {
199 | //_clipboardActionModeCallback2.onDestroyActionMode(_clipboardActionMode);
200 | _clipboardActionMode.finish();
201 | _clipboardActionMode = null;
202 | }
203 | }
204 |
205 | public void invalidateContentRect() {
206 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && _clipboardActionMode != null)
207 | _clipboardActionMode.invalidateContentRect();
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/codeeditor/src/main/java/cn/rbc/codeeditor/util/LinearSearchStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package cn.rbc.codeeditor.util;
10 |
11 | import cn.rbc.codeeditor.lang.Language;
12 |
13 | public class LinearSearchStrategy implements SearchStrategy {
14 | private int _unitsDone = 0;
15 |
16 | @Override
17 | // only applicable to replaceAll operation
18 | public int getProgress() {
19 | return _unitsDone;
20 | }
21 |
22 | @Override
23 | public int wrappedFind(Document src, String target, int start,
24 | boolean isCaseSensitive, boolean isWholeWord) {
25 |
26 | // search towards end of doc first...
27 | int foundOffset = find(src, target, start, src.length(),
28 | isCaseSensitive, isWholeWord);
29 | // ...then from beginning of doc
30 | if (foundOffset < 0) {
31 | foundOffset = find(src, target, 0, start,
32 | isCaseSensitive, isWholeWord);
33 | }
34 |
35 | return foundOffset;
36 | }
37 |
38 | @Override
39 | public int find(Document src, String target, int start, int end,
40 | boolean isCaseSensitive, boolean isWholeWord) {
41 | if (target.length() == 0) {
42 | return -1;
43 | }
44 | if (start < 0) {
45 | TextWarriorException.fail("TextBuffer.find: Invalid start position");
46 | start = 0;
47 | }
48 | if (end > src.length()) {
49 | TextWarriorException.fail("TextBuffer.find: Invalid end position");
50 | end = src.length();
51 | }
52 |
53 | end = Math.min(end, src.length() - target.length() + 1);
54 | int offset = start;
55 | while (offset < end) {
56 | if (equals(src, target, offset, isCaseSensitive) &&
57 | (!isWholeWord || isSandwichedByWhitespace(src, offset, target.length()))) {
58 | break;
59 | }
60 |
61 | ++offset;
62 | ++_unitsDone;
63 | }
64 |
65 | if (offset < end) {
66 | return offset;
67 | } else {
68 | return -1;
69 | }
70 | }
71 |
72 | @Override
73 | public int wrappedFindBackwards(Document src, String target, int start,
74 | boolean isCaseSensitive, boolean isWholeWord) {
75 |
76 | // search towards beginning of doc first...
77 | int foundOffset = findBackwards(src, target, start, -1,
78 | isCaseSensitive, isWholeWord);
79 | // ...then from end of doc
80 | if (foundOffset < 0) {
81 | foundOffset = findBackwards(src, target, src.length() - 1, start,
82 | isCaseSensitive, isWholeWord);
83 | }
84 |
85 | return foundOffset;
86 | }
87 |
88 |
89 | @Override
90 | public int findBackwards(Document src, String target, int start, int end,
91 | boolean isCaseSensitive, boolean isWholeWord) {
92 | if (target.length() == 0) {
93 | return -1;
94 | }
95 | if (start >= src.length()) {
96 | TextWarriorException.fail("Invalid start position given to TextBuffer.find");
97 | start = src.length() - 1;
98 | }
99 | if (end < -1) {
100 | TextWarriorException.fail("Invalid end position given to TextBuffer.find");
101 | end = -1;
102 | }
103 | int offset = Math.min(start, src.length() - target.length());
104 | while (offset > end) {
105 | if (equals(src, target, offset, isCaseSensitive) &&
106 | (!isWholeWord || isSandwichedByWhitespace(src, offset, target.length()))) {
107 | break;
108 | }
109 |
110 | --offset;
111 | }
112 |
113 | if (offset > end) {
114 | return offset;
115 | } else {
116 | return -1;
117 | }
118 | }
119 |
120 | @Override
121 | public Pair replaceAll(Document src, String searchText,
122 | String replacementText, int mark,
123 | boolean isCaseSensitive, boolean isWholeWord) {
124 | int replacementCount = 0;
125 | int anchor = mark;
126 | _unitsDone = 0;
127 |
128 | final char[] replacement = replacementText.toCharArray();
129 | int foundIndex = find(src, searchText, 0, src.length(),
130 | isCaseSensitive, isWholeWord);
131 | long timestamp = System.nanoTime();
132 |
133 | src.beginBatchEdit();
134 | while (foundIndex != -1) {
135 | src.deleteAt(foundIndex, searchText.length(), timestamp);
136 | src.insertBefore(replacement, foundIndex, timestamp);
137 | if (foundIndex < anchor) {
138 | // adjust anchor because of differences in doc length
139 | // after word replacement
140 | anchor += replacementText.length() - searchText.length();
141 | }
142 | ++replacementCount;
143 | _unitsDone += searchText.length(); //skip replaced chars
144 | foundIndex = find(
145 | src,
146 | searchText,
147 | foundIndex + replacementText.length(),
148 | src.length(),
149 | isCaseSensitive,
150 | isWholeWord);
151 | }
152 | src.endBatchEdit();
153 |
154 | return new Pair(replacementCount, Math.max(anchor, 0));
155 | }
156 |
157 |
158 | protected boolean equals(Document src, String target,
159 | int srcOffset, boolean isCaseSensitive) {
160 | if ((src.length() - srcOffset) < target.length()) {
161 | //compared range in src must at least be as long as target
162 | return false;
163 | }
164 |
165 | int i;
166 | for (i = 0; i < target.length(); ++i) {
167 | if (isCaseSensitive &&
168 | target.charAt(i) != src.charAt(i + srcOffset)) {
169 | return false;
170 | }
171 | // for case-insensitive search, compare both strings in lower case
172 | if (!isCaseSensitive &&
173 | Character.toLowerCase(target.charAt(i)) !=
174 | Character.toLowerCase(src.charAt(i + srcOffset))) {
175 | return false;
176 | }
177 |
178 | }
179 |
180 | return true;
181 | }
182 |
183 | /**
184 | * Checks if a word starting at startPosition with size length is bounded
185 | * by whitespace.
186 | */
187 | protected boolean isSandwichedByWhitespace(Document src,
188 | int start, int length) {
189 | Language charSet = Tokenizer.getLanguage();
190 | boolean startWithWhitespace = (start == 0) || charSet.isWhitespace(src.charAt(start - 1));
191 |
192 | int end = start + length;
193 | boolean endWithWhitespace = (end == src.length()) || charSet.isWhitespace(src.charAt(end));
194 |
195 | return (startWithWhitespace && endWithWhitespace);
196 | }
197 |
198 | }
199 |
--------------------------------------------------------------------------------