diff --git a/.travis.yml b/.travis.yml
index 8c09f5317f..4727539309 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,7 +12,7 @@ android:
components:
- platform-tools
- tools
- - build-tools-25.0.2
+ - build-tools-26.0.0
- android-25
- extra-android-m2repository
diff --git a/README.md b/README.md
index 28691c108d..45666bfccf 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@ Termux app
* [Termux on Google Play Store](https://play.google.com/store/apps/details?id=com.termux)
* [Termux on F-Droid](https://f-droid.org/repository/browse/?fdid=com.termux)
+* [Termux Wiki](https://wiki.termux.com/wiki/)
* [Termux Help](http://termux.com/help/)
* [Termux Google+ community](http://termux.com/community/)
diff --git a/app/build.gradle b/app/build.gradle
index 88e2be6011..901fa1c2cd 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -2,7 +2,7 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ buildToolsVersion "26.0.0"
dependencies {
compile 'com.android.support:support-annotations:25.3.1'
@@ -14,8 +14,8 @@ android {
applicationId "com.termux"
minSdkVersion 21
targetSdkVersion 25
- versionCode 48
- versionName "0.48"
+ versionCode 53
+ versionName "0.53"
}
buildTypes {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d875d5abe7..aacc24448c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -13,7 +13,7 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/termux/app/BackgroundJob.java b/app/src/main/java/com/termux/app/BackgroundJob.java
index bd76edc2fd..1ff2450eb4 100644
--- a/app/src/main/java/com/termux/app/BackgroundJob.java
+++ b/app/src/main/java/com/termux/app/BackgroundJob.java
@@ -116,8 +116,9 @@ public static String[] buildEnvironment(boolean failSafe, String cwd) {
final String langEnv = "LANG=en_US.UTF-8";
final String pathEnv = "PATH=" + TermuxService.PREFIX_PATH + "/bin:" + TermuxService.PREFIX_PATH + "/bin/applets";
final String pwdEnv = "PWD=" + cwd;
+ final String tmpdirEnv = "TMPDIR=" + TermuxService.PREFIX_PATH + "/tmp";
- return new String[]{termEnv, homeEnv, prefixEnv, ps1Env, ldEnv, langEnv, pathEnv, pwdEnv, androidRootEnv, androidDataEnv, externalStorageEnv};
+ return new String[]{termEnv, homeEnv, prefixEnv, ps1Env, ldEnv, langEnv, pathEnv, pwdEnv, androidRootEnv, androidDataEnv, externalStorageEnv, tmpdirEnv};
}
}
diff --git a/app/src/main/java/com/termux/app/TermuxActivity.java b/app/src/main/java/com/termux/app/TermuxActivity.java
index 8e6c7255db..c869ffeb88 100644
--- a/app/src/main/java/com/termux/app/TermuxActivity.java
+++ b/app/src/main/java/com/termux/app/TermuxActivity.java
@@ -397,7 +397,6 @@ public void onSessionFinished(final TerminalSession finishedSession) {
@Override
public void onClipboardText(TerminalSession session, String text) {
if (!mIsVisible) return;
- showToast("Clipboard:\n\"" + text + "\"", false);
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setPrimaryClip(new ClipData(null, new String[]{"text/plain"}, new ClipData.Item(text)));
}
diff --git a/build.gradle b/build.gradle
index 3ee2d98eba..ee9a47abee 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.3.1'
+ classpath 'com.android.tools.build:gradle:2.3.3'
}
}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index eac8c4a1e1..7a3265ee94 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index dd9949e124..f16d26666b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Mon Mar 06 01:34:12 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip
diff --git a/gradlew b/gradlew
index 4453ccea33..cccdd3d517 100755
--- a/gradlew
+++ b/gradlew
@@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
-warn ( ) {
+warn () {
echo "$*"
}
-die ( ) {
+die () {
echo
echo "$*"
echo
@@ -155,7 +155,7 @@ if $cygwin ; then
fi
# Escape application args
-save ( ) {
+save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
diff --git a/terminal-emulator/build.gradle b/terminal-emulator/build.gradle
index d10a39e15f..63ddeabee3 100644
--- a/terminal-emulator/build.gradle
+++ b/terminal-emulator/build.gradle
@@ -13,12 +13,12 @@ ext {
libraryDescription = 'The terminal emulator used in Termux'
siteUrl = 'https://github.com/termux/termux'
gitUrl = 'https://github.com/termux/termux.git'
- libraryVersion = '0.49'
+ libraryVersion = '0.50'
}
android {
compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ buildToolsVersion "26.0.0"
defaultConfig {
minSdkVersion 21
diff --git a/terminal-emulator/src/main/AndroidManifest.xml b/terminal-emulator/src/main/AndroidManifest.xml
index b931189d9f..a293cb643b 100644
--- a/terminal-emulator/src/main/AndroidManifest.xml
+++ b/terminal-emulator/src/main/AndroidManifest.xml
@@ -1,3 +1,2 @@
-
+
diff --git a/terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java b/terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java
index e172d38ea6..10c7321dd9 100644
--- a/terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java
+++ b/terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java
@@ -223,6 +223,7 @@ public final class TerminalEmulator {
private byte mUtf8ToFollow, mUtf8Index;
private final byte[] mUtf8InputBuffer = new byte[4];
+ private int mLastEmittedCodePoint = -1;
public final TerminalColors mColors = new TerminalColors();
@@ -419,10 +420,11 @@ private void processByte(byte byteToProcess) {
mUtf8Index = mUtf8ToFollow = 0;
if (codePoint >= 0x80 && codePoint <= 0x9F) {
- // Sequence decoded to a C1 control character which is the same as escape followed by
- // ((code & 0x7F) + 0x40).
- processCodePoint(/* escape (hexadecimal=0x1B, octal=033): */27);
- processCodePoint((codePoint & 0x7F) + 0x40);
+ // Sequence decoded to a C1 control character which we ignore. They are
+ // not used nowadays and increases the risk of messing up the terminal state
+ // on binary input. XTerm does not allow them in utf-8:
+ // "It is not possible to use a C1 control obtained from decoding the
+ // UTF-8 text" - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
} else {
switch (Character.getType(codePoint)) {
case Character.UNASSIGNED:
@@ -632,6 +634,7 @@ public void processCodePoint(int b) {
int bottom = Math.min(getArg(2, mRows, true) + 1, effectiveBottomMargin - 1) + effectiveTopMargin;
int right = Math.min(getArg(3, mColumns, true) + 1, effectiveRightMargin - 1) + effectiveLeftMargin;
if (mArgIndex >= 4) {
+ if (mArgIndex >= mArgs.length) mArgIndex = mArgs.length - 1;
for (int i = 4; i <= mArgIndex; i++) {
int bits = 0;
boolean setOrClear = true; // True if setting, false if clearing.
@@ -965,6 +968,7 @@ private void doCsiQuestionMark(int b) {
break;
case 'h':
case 'l':
+ if (mArgIndex >= mArgs.length) mArgIndex = mArgs.length - 1;
for (int i = 0; i <= mArgIndex; i++)
doDecSetOrReset(b == 'h', mArgs[i]);
break;
@@ -981,6 +985,7 @@ private void doCsiQuestionMark(int b) {
break;
case 'r':
case 's':
+ if (mArgIndex >= mArgs.length) mArgIndex = mArgs.length - 1;
for (int i = 0; i <= mArgIndex; i++) {
int externalBit = mArgs[i];
int internalBit = mapDecSetBitToInternalBit(externalBit);
@@ -1307,6 +1312,8 @@ private void saveCursor() {
state.mSavedCursorRow = mCursorRow;
state.mSavedCursorCol = mCursorCol;
state.mSavedEffect = mEffect;
+ state.mSavedForeColor = mForeColor;
+ state.mSavedBackColor = mBackColor;
state.mSavedDecFlags = mCurrentDecSetFlags;
state.mUseLineDrawingG0 = mUseLineDrawingG0;
state.mUseLineDrawingG1 = mUseLineDrawingG1;
@@ -1318,6 +1325,8 @@ private void restoreCursor() {
SavedScreenState state = (mScreen == mMainBuffer) ? mSavedStateMain : mSavedStateAlt;
setCursorRowCol(state.mSavedCursorRow, state.mSavedCursorCol);
mEffect = state.mSavedEffect;
+ mForeColor = state.mSavedForeColor;
+ mBackColor = state.mSavedBackColor;
int mask = (DECSET_BIT_AUTOWRAP | DECSET_BIT_ORIGIN_MODE);
mCurrentDecSetFlags = (mCurrentDecSetFlags & ~mask) | (state.mSavedDecFlags & mask);
mUseLineDrawingG0 = state.mUseLineDrawingG0;
@@ -1501,6 +1510,11 @@ private void doCsi(int b) {
case '`': // Horizontal position absolute (HPA - http://www.vt100.net/docs/vt510-rm/HPA).
setCursorColRespectingOriginMode(getArg0(1) - 1);
break;
+ case 'b': // Repeat the preceding graphic character Ps times (REP).
+ if (mLastEmittedCodePoint == -1) break;
+ final int numRepeat = getArg0(1);
+ for (int i = 0; i < numRepeat; i++) emitCodePoint(mLastEmittedCodePoint);
+ break;
case 'c': // Primary Device Attributes (http://www.vt100.net/docs/vt510-rm/DA1) if argument is missing or zero.
// The important part that may still be used by some (tmux stores this value but does not currently use it)
// is the first response parameter identifying the terminal service class, where we send 64 for "vt420".
@@ -1566,6 +1580,7 @@ private void doCsi(int b) {
// Also require that top + 2 <= bottom.
mTopMargin = Math.max(0, Math.min(getArg0(1) - 1, mRows - 2));
mBottomMargin = Math.max(mTopMargin + 2, Math.min(getArg1(mRows), mRows));
+
// DECSTBM moves the cursor to column 1, line 1 of the page respecting origin mode.
setCursorPosition(0, 0);
}
@@ -1639,6 +1654,7 @@ private void doCsi(int b) {
/** Select Graphic Rendition (SGR) - see http://en.wikipedia.org/wiki/ANSI_escape_code#graphics. */
private void selectGraphicRendition() {
+ if (mArgIndex >= mArgs.length) mArgIndex = mArgs.length - 1;
for (int i = 0; i <= mArgIndex; i++) {
int code = mArgs[i];
if (code < 0) {
@@ -2049,6 +2065,7 @@ private void logError(String errorType) {
buf.append(", escapeState=");
buf.append(mEscapeState);
boolean firstArg = true;
+ if (mArgIndex >= mArgs.length) mArgIndex = mArgs.length - 1;
for (int i = 0; i <= mArgIndex; i++) {
int value = mArgs[i];
if (value >= 0) {
@@ -2081,6 +2098,7 @@ private void finishSequence() {
* @param codePoint The code point of the character to display
*/
private void emitCodePoint(int codePoint) {
+ mLastEmittedCodePoint = codePoint;
if (mUseLineDrawingUsesG0 ? mUseLineDrawingG0 : mUseLineDrawingG1) {
// http://www.vt100.net/docs/vt102-ug/table5-15.html.
switch (codePoint) {
@@ -2263,8 +2281,8 @@ public void reset() {
mBottomMargin = mRows;
mRightMargin = mColumns;
mAboutToAutoWrap = false;
- mForeColor = TextStyle.COLOR_INDEX_FOREGROUND;
- mBackColor = TextStyle.COLOR_INDEX_BACKGROUND;
+ mForeColor = mSavedStateMain.mSavedForeColor = mSavedStateAlt.mSavedForeColor = TextStyle.COLOR_INDEX_FOREGROUND;
+ mBackColor = mSavedStateMain.mSavedBackColor = mSavedStateAlt.mSavedBackColor = TextStyle.COLOR_INDEX_BACKGROUND;
setDefaultTabStops();
mUseLineDrawingG0 = mUseLineDrawingG1 = false;
@@ -2318,7 +2336,7 @@ public void paste(String text) {
static final class SavedScreenState {
/** Saved state of the cursor position, Used to implement the save/restore cursor position escape sequences. */
int mSavedCursorRow, mSavedCursorCol;
- int mSavedEffect;
+ int mSavedEffect, mSavedForeColor, mSavedBackColor;
int mSavedDecFlags;
boolean mUseLineDrawingG0, mUseLineDrawingG1, mUseLineDrawingUsesG0 = true;
}
diff --git a/terminal-emulator/src/test/java/com/termux/terminal/ControlSequenceIntroducerTest.java b/terminal-emulator/src/test/java/com/termux/terminal/ControlSequenceIntroducerTest.java
index 127b95390c..88b8e0269c 100644
--- a/terminal-emulator/src/test/java/com/termux/terminal/ControlSequenceIntroducerTest.java
+++ b/terminal-emulator/src/test/java/com/termux/terminal/ControlSequenceIntroducerTest.java
@@ -29,4 +29,21 @@ public void testCsiX() {
withTerminalSized(13, 2).enterString("abcdefghijkl\b\b\b\b\b\033[20X").assertLinesAre("abcdefg ", " ");
}
+ /** CSI Pm m Set SGR parameter(s) from semicolon-separated list Pm. */
+ public void testCsiSGRParameters() {
+ // Set more parameters (19) than supported (16). Additional parameters should be silently consumed.
+ withTerminalSized(3, 2).enterString("\033[0;38;2;255;255;255;48;2;0;0;0;1;2;3;4;5;7;8;9mabc").assertLinesAre("abc", " ");
+ }
+
+ /** CSI Ps b Repeat the preceding graphic character Ps times (REP). */
+ public void testRepeat() {
+ withTerminalSized(3, 2).enterString("a\033[b").assertLinesAre("aa ", " ");
+ withTerminalSized(3, 2).enterString("a\033[2b").assertLinesAre("aaa", " ");
+ // When no char has been output we ignore REP:
+ withTerminalSized(3, 2).enterString("\033[b").assertLinesAre(" ", " ");
+ // This shows that REP outputs the last emitted code point and not the one relative to the
+ // current cursor position:
+ withTerminalSized(5, 2).enterString("abcde\033[2G\033[2b\n").assertLinesAre("aeede", " ");
+ }
+
}
diff --git a/terminal-emulator/src/test/java/com/termux/terminal/CursorAndScreenTest.java b/terminal-emulator/src/test/java/com/termux/terminal/CursorAndScreenTest.java
index 567e627b9e..92c41f0f4e 100644
--- a/terminal-emulator/src/test/java/com/termux/terminal/CursorAndScreenTest.java
+++ b/terminal-emulator/src/test/java/com/termux/terminal/CursorAndScreenTest.java
@@ -227,4 +227,44 @@ public void testBackspaceAcrossWrappedLines() {
withTerminalSized(3, 3).enterString("\b\b\b\bhi").assertLinesAre("hi ", " ", " ");
}
+ public void testCursorSaveRestoreLocation() {
+ // DEC save/restore
+ withTerminalSized(4, 2).enterString("t\0337est\r\nme\0338ry ").assertLinesAre("try ", "me ");
+ // ANSI.SYS save/restore
+ withTerminalSized(4, 2).enterString("t\033[sest\r\nme\033[ury ").assertLinesAre("try ", "me ");
+ // Alternate screen enter/exit
+ withTerminalSized(4, 2).enterString("t\033[?1049h\033[Hest\r\nme").assertLinesAre("est ", "me ").enterString("\033[?1049lry").assertLinesAre("try ", " ");
+ }
+
+ public void testCursorSaveRestoreTextStyle() {
+ long s;
+
+ // DEC save/restore
+ withTerminalSized(4, 2).enterString("\033[31;42;4m..\0337\033[36;47;24m\0338..");
+ s = getStyleAt(0, 3);
+ Assert.assertEquals(1, TextStyle.decodeForeColor(s));
+ Assert.assertEquals(2, TextStyle.decodeBackColor(s));
+ Assert.assertEquals(TextStyle.CHARACTER_ATTRIBUTE_UNDERLINE, TextStyle.decodeEffect(s));
+
+ // ANSI.SYS save/restore
+ withTerminalSized(4, 2).enterString("\033[31;42;4m..\033[s\033[36;47;24m\033[u..");
+ s = getStyleAt(0, 3);
+ Assert.assertEquals(1, TextStyle.decodeForeColor(s));
+ Assert.assertEquals(2, TextStyle.decodeBackColor(s));
+ Assert.assertEquals(TextStyle.CHARACTER_ATTRIBUTE_UNDERLINE, TextStyle.decodeEffect(s));
+
+ // Alternate screen enter/exit
+ withTerminalSized(4, 2);
+ enterString("\033[31;42;4m..\033[?1049h\033[H\033[36;47;24m.");
+ s = getStyleAt(0, 0);
+ Assert.assertEquals(6, TextStyle.decodeForeColor(s));
+ Assert.assertEquals(7, TextStyle.decodeBackColor(s));
+ Assert.assertEquals(0, TextStyle.decodeEffect(s));
+ enterString("\033[?1049l..");
+ s = getStyleAt(0, 3);
+ Assert.assertEquals(1, TextStyle.decodeForeColor(s));
+ Assert.assertEquals(2, TextStyle.decodeBackColor(s));
+ Assert.assertEquals(TextStyle.CHARACTER_ATTRIBUTE_UNDERLINE, TextStyle.decodeEffect(s));
+ }
+
}
diff --git a/terminal-view/build.gradle b/terminal-view/build.gradle
index 7e4c7cfa5e..5f2c367407 100644
--- a/terminal-view/build.gradle
+++ b/terminal-view/build.gradle
@@ -18,7 +18,7 @@ ext {
android {
compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ buildToolsVersion "26.0.0"
dependencies {
compile 'com.android.support:support-annotations:25.3.1'
diff --git a/terminal-view/src/main/AndroidManifest.xml b/terminal-view/src/main/AndroidManifest.xml
index a312303c54..f2b0725df4 100644
--- a/terminal-view/src/main/AndroidManifest.xml
+++ b/terminal-view/src/main/AndroidManifest.xml
@@ -1,3 +1,2 @@
-
+
diff --git a/terminal-view/src/main/java/com/termux/view/TerminalView.java b/terminal-view/src/main/java/com/termux/view/TerminalView.java
index fb01874776..91d0762d90 100644
--- a/terminal-view/src/main/java/com/termux/view/TerminalView.java
+++ b/terminal-view/src/main/java/com/termux/view/TerminalView.java
@@ -834,6 +834,10 @@ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ if (!mIsSelectingText) {
+ // Fix issue where the dialog is pressed while being dismissed.
+ return true;
+ }
switch (item.getItemId()) {
case 1:
String selectedText = mEmulator.getSelectedText(mSelX1, mSelY1, mSelX2, mSelY2).trim();