Compare commits
10 Commits
e27f9fa979
...
2f40df91e5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f40df91e5 | ||
|
|
755b752a95 | ||
|
|
67f4891580 | ||
|
|
7b19cd2f5a | ||
|
|
882da34fcd | ||
|
|
8e3a8980a8 | ||
|
|
e4385832b7 | ||
|
|
3b5018b4c7 | ||
|
|
c84d4804c8 | ||
|
|
6727bbecc4 |
@@ -6,7 +6,7 @@ on:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
build:
|
||||
attach-apks:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -21,15 +21,23 @@ jobs:
|
||||
with:
|
||||
ref: ${{ env.GITHUB_REF }}
|
||||
|
||||
- name: Build
|
||||
- name: Build and attach APKs to release
|
||||
shell: bash {0}
|
||||
env:
|
||||
PACKAGE_VARIANT: ${{ matrix.package_variant }}
|
||||
run: |
|
||||
exit_on_error() {
|
||||
echo "$1"
|
||||
echo "Deleting '$RELEASE_VERSION_NAME' release and '$GITHUB_REF' tag"
|
||||
hub release delete "$RELEASE_VERSION_NAME"
|
||||
git push --delete origin "$GITHUB_REF"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "Setting vars"
|
||||
RELEASE_VERSION_NAME="${GITHUB_REF/refs\/tags\//}"
|
||||
if ! printf "%s" "${RELEASE_VERSION_NAME/v/}" | grep -qP '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'; then
|
||||
echo "The versionName '${RELEASE_VERSION_NAME/v/}' is not a valid version as per semantic version '2.0.0' spec in the format 'major.minor.patch(-prerelease)(+buildmetadata)'. https://semver.org/spec/v2.0.0.html."
|
||||
exit 1
|
||||
exit_on_error "The versionName '${RELEASE_VERSION_NAME/v/}' is not a valid version as per semantic version '2.0.0' spec in the format 'major.minor.patch(-prerelease)(+buildmetadata)'. https://semver.org/spec/v2.0.0.html."
|
||||
fi
|
||||
|
||||
APK_DIR_PATH="./app/build/outputs/apk/debug"
|
||||
@@ -39,35 +47,38 @@ jobs:
|
||||
echo "Building APKs for 'APK_VERSION_TAG' release"
|
||||
export TERMUX_APK_VERSION_TAG="$APK_VERSION_TAG" # Used by app/build.gradle
|
||||
export TERMUX_PACKAGE_VARIANT="${{ env.PACKAGE_VARIANT }}" # Used by app/build.gradle
|
||||
./gradlew assembleDebug
|
||||
if ! ./gradlew assembleDebug; then
|
||||
exit_on_error "Build failed for '$APK_VERSION_TAG' release."
|
||||
fi
|
||||
|
||||
echo "Validating APKs"
|
||||
for abi in universal arm64-v8a armeabi-v7a x86_64 x86; do
|
||||
if ! test -f "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_$abi.apk"; then
|
||||
files_found="$(ls "$APK_DIR_PATH")"
|
||||
echo "Failed to find built APK at '$APK_DIR_PATH/${APK_BASENAME_PREFIX}_$abi.apk'. Files found: "$'\n'"$files_found"
|
||||
exit 1
|
||||
exit_on_error "Failed to find built APK at '$APK_DIR_PATH/${APK_BASENAME_PREFIX}_$abi.apk'. Files found: "$'\n'"$files_found"
|
||||
fi
|
||||
done
|
||||
- name: Upload APKs to GitHub artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.package_variant }}
|
||||
path: ./app/build/outputs/apk/debug/*.apk
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
- name: Upload APKs to release
|
||||
uses: termux/upload-release-action@v4.1.0
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: "**/*.apk"
|
||||
file_glob: true
|
||||
release_name:
|
||||
tag: ${{ github.event.release.tag_name }}
|
||||
checksums: sha256,sha512,md5
|
||||
|
||||
echo "Generating sha25sums file"
|
||||
if ! (cd "$APK_DIR_PATH"; sha256sum \
|
||||
"${APK_BASENAME_PREFIX}_universal.apk" \
|
||||
"${APK_BASENAME_PREFIX}_arm64-v8a.apk" \
|
||||
"${APK_BASENAME_PREFIX}_armeabi-v7a.apk" \
|
||||
"${APK_BASENAME_PREFIX}_x86_64.apk" \
|
||||
"${APK_BASENAME_PREFIX}_x86.apk" \
|
||||
> "${APK_BASENAME_PREFIX}_sha256sums"); then
|
||||
exit_on_error "Generate sha25sums failed for '$APK_VERSION_TAG' release."
|
||||
fi
|
||||
|
||||
echo "Attaching APKs to github release"
|
||||
if ! hub release edit \
|
||||
-m "" \
|
||||
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_universal.apk" \
|
||||
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_arm64-v8a.apk" \
|
||||
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_armeabi-v7a.apk" \
|
||||
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_x86_64.apk" \
|
||||
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_x86.apk" \
|
||||
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_sha256sums" \
|
||||
"$RELEASE_VERSION_NAME"; then
|
||||
exit_on_error "Attach APKs to release failed for '$APK_VERSION_TAG' release."
|
||||
fi
|
||||
|
||||
12
.github/workflows/debug_build.yml
vendored
12
.github/workflows/debug_build.yml
vendored
@@ -78,7 +78,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Attach universal APK file
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.APK_BASENAME_PREFIX }}_universal
|
||||
path: |
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
${{ env.APK_DIR_PATH }}/output-metadata.json
|
||||
|
||||
- name: Attach arm64-v8a APK file
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.APK_BASENAME_PREFIX }}_arm64-v8a
|
||||
path: |
|
||||
@@ -94,7 +94,7 @@ jobs:
|
||||
${{ env.APK_DIR_PATH }}/output-metadata.json
|
||||
|
||||
- name: Attach armeabi-v7a APK file
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.APK_BASENAME_PREFIX }}_armeabi-v7a
|
||||
path: |
|
||||
@@ -102,7 +102,7 @@ jobs:
|
||||
${{ env.APK_DIR_PATH }}/output-metadata.json
|
||||
|
||||
- name: Attach x86_64 APK file
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.APK_BASENAME_PREFIX }}_x86_64
|
||||
path: |
|
||||
@@ -110,7 +110,7 @@ jobs:
|
||||
${{ env.APK_DIR_PATH }}/output-metadata.json
|
||||
|
||||
- name: Attach x86 APK file
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.APK_BASENAME_PREFIX }}_x86
|
||||
path: |
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
${{ env.APK_DIR_PATH }}/output-metadata.json
|
||||
|
||||
- name: Attach sha256sums file
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.APK_BASENAME_PREFIX }}_sha256sums
|
||||
path: |
|
||||
|
||||
@@ -16,4 +16,4 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: gradle/wrapper-validation-action@v1
|
||||
- uses: gradle/wrapper-validation-action@v3
|
||||
|
||||
28
README.md
28
README.md
@@ -91,7 +91,8 @@ Both universal and architecture specific APKs are released. The APK and bootstra
|
||||
|
||||
The [test key](https://github.com/termux/termux-app/blob/master/app/testkey_untrusted.jks) shall not be used to impersonate @termux and can't be used for this anyway. This key is not trusted by us and it is quite easy to detect its use in user generated content.
|
||||
|
||||
Keystore information:
|
||||
<details>
|
||||
<summary>Keystore information</summary>
|
||||
|
||||
```
|
||||
Alias name: alias
|
||||
@@ -111,6 +112,8 @@ Subject Public Key Algorithm: 2048-bit RSA key
|
||||
Version: 3
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Google Play Store **(Deprecated)**
|
||||
|
||||
**Termux and its plugins are no longer updated on [Google Play Store](https://play.google.com/store/apps/details?id=com.termux) due to [android 10 issues](https://github.com/termux/termux-packages/wiki/Termux-and-Android-10) and have been deprecated.** The last version released for Android `>= 7` was `v0.101`. **It is highly recommended to not install Termux apps from Play Store any more.**
|
||||
@@ -174,7 +177,7 @@ The main ones are the following.
|
||||
- [Termux Reddit community](https://reddit.com/r/termux)
|
||||
- [Termux User Matrix Channel](https://matrix.to/#/#termux_termux:gitter.im) ([Gitter](https://gitter.im/termux/termux))
|
||||
- [Termux Dev Matrix Channel](https://matrix.to/#/#termux_dev:gitter.im) ([Gitter](https://gitter.im/termux/dev))
|
||||
- [Termux Twitter](https://twitter.com/termuxdevs)
|
||||
- [Termux X (Twitter)](https://twitter.com/termuxdevs)
|
||||
- [Termux Support Email](mailto:support@termux.dev)
|
||||
|
||||
### Wikis
|
||||
@@ -261,7 +264,21 @@ The main Termux constants are defined by [`TermuxConstants`](https://github.com/
|
||||
|
||||
Check [Termux Libraries](https://github.com/termux/termux-app/wiki/Termux-Libraries) for how to import termux libraries in plugin apps and [Forking and Local Development](https://github.com/termux/termux-app/wiki/Termux-Libraries#forking-and-local-development) for how to update termux libraries for plugins.
|
||||
|
||||
Commit messages **must** use [Conventional Commits](https://www.conventionalcommits.org) specs so that chagelogs can automatically be generated by the [`create-conventional-changelog`](https://github.com/termux/create-conventional-changelog) script, check its repo for further details on the spec. Use the following `types` as `Added: Add foo`, `Added|Fixed: Add foo and fix bar`, `Changed!: Change baz as a breaking change`, etc. You can optionally add a scope as well, like `Fixed(terminal): Some bug`. The space after `:` is necessary.
|
||||
The `versionName` in `build.gradle` files of Termux and its plugin apps must follow the [semantic version `2.0.0` spec](https://semver.org/spec/v2.0.0.html) in the format `major.minor.patch(-prerelease)(+buildmetadata)`. When bumping `versionName` in `build.gradle` files and when creating a tag for new releases on GitHub, make sure to include the patch number as well, like `v0.1.0` instead of just `v0.1`. The `build.gradle` files and `attach_debug_apks_to_release` workflow validates the version as well and the build/attachment will fail if `versionName` does not follow the spec.
|
||||
|
||||
### Commit Messages Guidelines
|
||||
|
||||
Commit messages **must** use the [Conventional Commits](https://www.conventionalcommits.org) spec so that chagelogs as per the [Keep a Changelog](https://github.com/olivierlacan/keep-a-changelog) spec can automatically be generated by the [`create-conventional-changelog`](https://github.com/termux/create-conventional-changelog) script, check its repo for further details on the spec. **The first letter for `type` and `description` must be capital and description should be in the present tense.** The space after the colon `:` is necessary. For a breaking change, add an exclamation mark `!` before the colon `:`, so that it is highlighted in the chagelog automatically.
|
||||
|
||||
```
|
||||
<type>[optional scope]: <description>
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer(s)]
|
||||
```
|
||||
|
||||
**Only the `types` listed below must be used exactly as they are used in the changelog headings.** For example, `Added: Add foo`, `Added|Fixed: Add foo and fix bar`, `Changed!: Change baz as a breaking change`, etc. You can optionally add a scope as well, like `Fixed(terminal): Fix some bug`. **Do not use anything else as type, like `add` instead of `Added`, etc.**
|
||||
|
||||
- **Added** for new features.
|
||||
- **Changed** for changes in existing functionality.
|
||||
@@ -269,11 +286,6 @@ Commit messages **must** use [Conventional Commits](https://www.conventionalcomm
|
||||
- **Removed** for now removed features.
|
||||
- **Fixed** for any bug fixes.
|
||||
- **Security** in case of vulnerabilities.
|
||||
- **Docs** for updating documentation.
|
||||
|
||||
Changelogs for releases are generated based on [Keep a Changelog](https://github.com/olivierlacan/keep-a-changelog) specs.
|
||||
|
||||
The `versionName` in `build.gradle` files of Termux and its plugin apps must follow the [semantic version `2.0.0` spec](https://semver.org/spec/v2.0.0.html) in the format `major.minor.patch(-prerelease)(+buildmetadata)`. When bumping `versionName` in `build.gradle` files and when creating a tag for new releases on GitHub, make sure to include the patch number as well, like `v0.1.0` instead of just `v0.1`. The `build.gradle` files and `attach_debug_apks_to_release` workflow validates the version as well and the build/attachment will fail if `versionName` does not follow the spec.
|
||||
##
|
||||
|
||||
|
||||
|
||||
@@ -11,11 +11,37 @@ public final class TerminalRow {
|
||||
|
||||
private static final float SPARE_CAPACITY_FACTOR = 1.5f;
|
||||
|
||||
/**
|
||||
* Max combining characters that can exist in a column, that are separate from the base character
|
||||
* itself. Any additional combining characters will be ignored and not added to the column.
|
||||
*
|
||||
* There does not seem to be limit in unicode standard for max number of combination characters
|
||||
* that can be combined but such characters are primarily under 10.
|
||||
*
|
||||
* "Section 3.6 Combination" of unicode standard contains combining characters info.
|
||||
* - https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf
|
||||
* - https://en.wikipedia.org/wiki/Combining_character#Unicode_ranges
|
||||
* - https://stackoverflow.com/questions/71237212/what-is-the-maximum-number-of-unicode-combined-characters-that-may-be-needed-to
|
||||
*
|
||||
* UAX15-D3 Stream-Safe Text Format limits to max 30 combining characters.
|
||||
* > The value of 30 is chosen to be significantly beyond what is required for any linguistic or technical usage.
|
||||
* > While it would have been feasible to chose a smaller number, this value provides a very wide margin,
|
||||
* > yet is well within the buffer size limits of practical implementations.
|
||||
* - https://unicode.org/reports/tr15/#Stream_Safe_Text_Format
|
||||
* - https://stackoverflow.com/a/11983435/14686958
|
||||
*
|
||||
* We choose the value 15 because it should be enough for terminal based applications and keep
|
||||
* the memory usage low for a terminal row, won't affect performance or cause terminal to
|
||||
* lag or hang, and will keep malicious applications from causing harm. The value can be
|
||||
* increased if ever needed for legitimate applications.
|
||||
*/
|
||||
private static final int MAX_COMBINING_CHARACTERS_PER_COLUMN = 15;
|
||||
|
||||
/** The number of columns in this terminal row. */
|
||||
private final int mColumns;
|
||||
/** The text filling this terminal row. */
|
||||
public char[] mText;
|
||||
/** The number of java char:s used in {@link #mText}. */
|
||||
/** The number of java chars used in {@link #mText}. */
|
||||
private short mSpaceUsed;
|
||||
/** If this row has been line wrapped due to text output at the end of line. */
|
||||
boolean mLineWrap;
|
||||
@@ -163,18 +189,25 @@ public final class TerminalRow {
|
||||
// Get the number of elements in the mText array this column uses now
|
||||
int oldCharactersUsedForColumn;
|
||||
if (columnToSet + oldCodePointDisplayWidth < mColumns) {
|
||||
oldCharactersUsedForColumn = findStartOfColumn(columnToSet + oldCodePointDisplayWidth) - oldStartOfColumnIndex;
|
||||
int oldEndOfColumnIndex = findStartOfColumn(columnToSet + oldCodePointDisplayWidth);
|
||||
oldCharactersUsedForColumn = oldEndOfColumnIndex - oldStartOfColumnIndex;
|
||||
} else {
|
||||
// Last character.
|
||||
oldCharactersUsedForColumn = mSpaceUsed - oldStartOfColumnIndex;
|
||||
}
|
||||
|
||||
// If MAX_COMBINING_CHARACTERS_PER_COLUMN already exist in column, then ignore adding additional combining characters.
|
||||
if (newIsCombining) {
|
||||
int combiningCharsCount = WcWidth.zeroWidthCharsCount(mText, oldStartOfColumnIndex, oldStartOfColumnIndex + oldCharactersUsedForColumn);
|
||||
if (combiningCharsCount >= MAX_COMBINING_CHARACTERS_PER_COLUMN)
|
||||
return;
|
||||
}
|
||||
|
||||
// Find how many chars this column will need
|
||||
int newCharactersUsedForColumn = Character.charCount(codePoint);
|
||||
if (newIsCombining) {
|
||||
// Combining characters are added to the contents of the column instead of overwriting them, so that they
|
||||
// modify the existing contents.
|
||||
// FIXME: Put a limit of combining characters.
|
||||
// FIXME: Unassigned characters also get width=0.
|
||||
newCharactersUsedForColumn += oldCharactersUsedForColumn;
|
||||
}
|
||||
@@ -189,7 +222,7 @@ public final class TerminalRow {
|
||||
if (mSpaceUsed + javaCharDifference > text.length) {
|
||||
// We need to grow the array
|
||||
char[] newText = new char[text.length + mColumns];
|
||||
System.arraycopy(text, 0, newText, 0, oldStartOfColumnIndex + oldCharactersUsedForColumn);
|
||||
System.arraycopy(text, 0, newText, 0, oldNextColumnIndex);
|
||||
System.arraycopy(text, oldNextColumnIndex, newText, newNextColumnIndex, oldCharactersAfterColumn);
|
||||
mText = text = newText;
|
||||
} else {
|
||||
|
||||
@@ -538,4 +538,29 @@ public final class WcWidth {
|
||||
return Character.isHighSurrogate(c) ? width(Character.toCodePoint(c, chars[index + 1])) : width(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* The zero width characters count like combining characters in the `chars` array from start
|
||||
* index to end index (exclusive).
|
||||
*/
|
||||
public static int zeroWidthCharsCount(char[] chars, int start, int end) {
|
||||
if (start < 0 || start >= chars.length)
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
for (int i = start; i < end && i < chars.length;) {
|
||||
if (Character.isHighSurrogate(chars[i])) {
|
||||
if (width(Character.toCodePoint(chars[i], chars[i + 1])) <= 0) {
|
||||
count++;
|
||||
}
|
||||
i += 2;
|
||||
} else {
|
||||
if (width(chars[i]) <= 0) {
|
||||
count++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user