Reformat code project-wide (getting rid of tabs)

This commit is contained in:
Fredrik Fornwall
2016-06-28 01:03:03 +02:00
parent d72fd579ee
commit 2db6923bc4
28 changed files with 6000 additions and 5748 deletions

231
.idea/codeStyleSettings.xml generated Normal file
View File

@@ -0,0 +1,231 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value>
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings>
<Objective-C-extensions>
<option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" />
<option name="RELEASE_STYLE" value="IVAR" />
<option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" />
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" />
<pair source="c" header="h" />
</extensions>
</Objective-C-extensions>
<XML>
<option name="XML_KEEP_LINE_BREAKS" value="false" />
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
<option name="XML_SPACE_INSIDE_EMPTY_TAG" value="true" />
</XML>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</value>
</option>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default (1)" />
</component>
</project>

View File

@@ -21,7 +21,7 @@ public final class BackgroundJob {
public BackgroundJob(File cwd, File fileToExecute, String[] args) throws IOException { public BackgroundJob(File cwd, File fileToExecute, String[] args) throws IOException {
String[] env = buildEnvironment(false, cwd.getAbsolutePath()); String[] env = buildEnvironment(false, cwd.getAbsolutePath());
String[] progArray = new String[args.length+1]; String[] progArray = new String[args.length + 1];
mProcess = Runtime.getRuntime().exec(progArray, env, cwd); mProcess = Runtime.getRuntime().exec(progArray, env, cwd);
@@ -97,7 +97,7 @@ public final class BackgroundJob {
if (failSafe) { if (failSafe) {
// Keep the default path so that system binaries can be used in the failsafe session. // Keep the default path so that system binaries can be used in the failsafe session.
final String pathEnv = "PATH=" + System.getenv("PATH"); final String pathEnv = "PATH=" + System.getenv("PATH");
return new String[] { termEnv, homeEnv, prefixEnv, androidRootEnv, androidDataEnv, pathEnv, externalStorageEnv }; return new String[]{termEnv, homeEnv, prefixEnv, androidRootEnv, androidDataEnv, pathEnv, externalStorageEnv};
} else { } else {
final String ps1Env = "PS1=$ "; final String ps1Env = "PS1=$ ";
final String ldEnv = "LD_LIBRARY_PATH=" + TermuxService.PREFIX_PATH + "/lib"; final String ldEnv = "LD_LIBRARY_PATH=" + TermuxService.PREFIX_PATH + "/lib";
@@ -105,7 +105,7 @@ public final class BackgroundJob {
final String pathEnv = "PATH=" + TermuxService.PREFIX_PATH + "/bin:" + TermuxService.PREFIX_PATH + "/bin/applets"; final String pathEnv = "PATH=" + TermuxService.PREFIX_PATH + "/bin:" + TermuxService.PREFIX_PATH + "/bin/applets";
final String pwdEnv = "PWD=" + cwd; final String pwdEnv = "PWD=" + cwd;
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};
} }
} }

View File

@@ -31,14 +31,29 @@ public final class ExtraKeysView extends GridLayout {
int keyCode = 0; int keyCode = 0;
String chars = null; String chars = null;
switch (keyName) { switch (keyName) {
case "ESC": keyCode = KeyEvent.KEYCODE_ESCAPE; break; case "ESC":
case "TAB": keyCode = KeyEvent.KEYCODE_TAB; break; keyCode = KeyEvent.KEYCODE_ESCAPE;
case "": keyCode = KeyEvent.KEYCODE_DPAD_UP; break; break;
case "": keyCode = KeyEvent.KEYCODE_DPAD_LEFT; break; case "TAB":
case "": keyCode = KeyEvent.KEYCODE_DPAD_RIGHT; break; keyCode = KeyEvent.KEYCODE_TAB;
case "": keyCode = KeyEvent.KEYCODE_DPAD_DOWN; break; break;
case "": chars = "-"; break; case "":
default: chars = keyName; keyCode = KeyEvent.KEYCODE_DPAD_UP;
break;
case "":
keyCode = KeyEvent.KEYCODE_DPAD_LEFT;
break;
case "":
keyCode = KeyEvent.KEYCODE_DPAD_RIGHT;
break;
case "":
keyCode = KeyEvent.KEYCODE_DPAD_DOWN;
break;
case "":
chars = "-";
break;
default:
chars = keyName;
} }
if (keyCode > 0) { if (keyCode > 0) {

View File

@@ -79,7 +79,7 @@ import java.util.regex.Pattern;
/** /**
* A terminal emulator activity. * A terminal emulator activity.
* * <p/>
* See * See
* <ul> * <ul>
* <li>http://www.mongrel-phones.com.au/default/how_to_make_a_local_service_and_bind_to_it_in_android</li> * <li>http://www.mongrel-phones.com.au/default/how_to_make_a_local_service_and_bind_to_it_in_android</li>
@@ -105,7 +105,9 @@ public final class TermuxActivity extends Activity implements ServiceConnection
private static final String RELOAD_STYLE_ACTION = "com.termux.app.reload_style"; private static final String RELOAD_STYLE_ACTION = "com.termux.app.reload_style";
/** The main view of the activity showing the terminal. Initialized in onCreate(). */ /** The main view of the activity showing the terminal. Initialized in onCreate(). */
@SuppressWarnings("NullableProblems") @NonNull TerminalView mTerminalView; @SuppressWarnings("NullableProblems")
@NonNull
TerminalView mTerminalView;
ExtraKeysView mExtraKeysView; ExtraKeysView mExtraKeysView;
@@ -143,7 +145,8 @@ public final class TermuxActivity extends Activity implements ServiceConnection
if (mIsVisible) { if (mIsVisible) {
String whatToReload = intent.getStringExtra(RELOAD_STYLE_ACTION); String whatToReload = intent.getStringExtra(RELOAD_STYLE_ACTION);
if ("storage".equals(whatToReload)) { if ("storage".equals(whatToReload)) {
if (ensureStoragePermissionGranted()) TermuxInstaller.setupStorageSymlinks(TermuxActivity.this); if (ensureStoragePermissionGranted())
TermuxInstaller.setupStorageSymlinks(TermuxActivity.this);
return; return;
} }
checkForFontAndColors(); checkForFontAndColors();
@@ -320,7 +323,8 @@ public final class TermuxActivity extends Activity implements ServiceConnection
Intent serviceIntent = new Intent(this, TermuxService.class); Intent serviceIntent = new Intent(this, TermuxService.class);
// Start the service and make it run regardless of who is bound to it: // Start the service and make it run regardless of who is bound to it:
startService(serviceIntent); startService(serviceIntent);
if (!bindService(serviceIntent, this, 0)) throw new RuntimeException("bindService() failed"); if (!bindService(serviceIntent, this, 0))
throw new RuntimeException("bindService() failed");
checkForFontAndColors(); checkForFontAndColors();
@@ -376,7 +380,8 @@ public final class TermuxActivity extends Activity implements ServiceConnection
// Show toast for non-current sessions that exit. // Show toast for non-current sessions that exit.
int indexOfSession = mTermService.getSessions().indexOf(finishedSession); int indexOfSession = mTermService.getSessions().indexOf(finishedSession);
// Verify that session was not removed before we got told about it finishing: // Verify that session was not removed before we got told about it finishing:
if (indexOfSession >= 0) showToast(toToastTitle(finishedSession) + " - exited", true); if (indexOfSession >= 0)
showToast(toToastTitle(finishedSession) + " - exited", true);
} }
mListViewAdapter.notifyDataSetChanged(); mListViewAdapter.notifyDataSetChanged();
} }
@@ -386,7 +391,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
if (!mIsVisible) return; if (!mIsVisible) return;
showToast("Clipboard:\n\"" + text + "\"", false); showToast("Clipboard:\n\"" + text + "\"", false);
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setPrimaryClip(new ClipData(null, new String[] { "text/plain" }, new ClipData.Item(text))); clipboard.setPrimaryClip(new ClipData(null, new String[]{"text/plain"}, new ClipData.Item(text)));
} }
@Override @Override
@@ -535,7 +540,8 @@ public final class TermuxActivity extends Activity implements ServiceConnection
} }
} }
@Nullable TerminalSession getCurrentTermSession() { @Nullable
TerminalSession getCurrentTermSession() {
return mTerminalView.getCurrentSession(); return mTerminalView.getCurrentSession();
} }
@@ -695,7 +701,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
public void onClick(DialogInterface di, int which) { public void onClick(DialogInterface di, int which) {
String url = (String) urls[which]; String url = (String) urls[which];
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setPrimaryClip(new ClipData(null, new String[] { "text/plain" }, new ClipData.Item(url))); clipboard.setPrimaryClip(new ClipData(null, new String[]{"text/plain"}, new ClipData.Item(url)));
Toast.makeText(TermuxActivity.this, R.string.select_url_copied_to_clipboard, Toast.LENGTH_LONG).show(); Toast.makeText(TermuxActivity.this, R.string.select_url_copied_to_clipboard, Toast.LENGTH_LONG).show();
} }
}).setTitle(R.string.select_url_dialog_title).create(); }).setTitle(R.string.select_url_dialog_title).create();
@@ -819,7 +825,8 @@ public final class TermuxActivity extends Activity implements ServiceConnection
ClipData clipData = clipboard.getPrimaryClip(); ClipData clipData = clipboard.getPrimaryClip();
if (clipData == null) return; if (clipData == null) return;
CharSequence paste = clipData.getItemAt(0).coerceToText(this); CharSequence paste = clipData.getItemAt(0).coerceToText(this);
if (!TextUtils.isEmpty(paste)) getCurrentTermSession().getEmulator().paste(paste.toString()); if (!TextUtils.isEmpty(paste))
getCurrentTermSession().getEmulator().paste(paste.toString());
} }
/** The current session as stored or the last one if that does not exist. */ /** The current session as stored or the last one if that does not exist. */

View File

@@ -31,21 +31,21 @@ import java.util.zip.ZipInputStream;
/** /**
* Install the Termux bootstrap packages if necessary by following the below steps: * Install the Termux bootstrap packages if necessary by following the below steps:
* * <p/>
* (1) If $PREFIX already exist, assume that it is correct and be done. Note that this relies on that we do not create a * (1) If $PREFIX already exist, assume that it is correct and be done. Note that this relies on that we do not create a
* broken $PREFIX folder below. * broken $PREFIX folder below.
* * <p/>
* (2) A progress dialog is shown with "Installing..." message and a spinner. * (2) A progress dialog is shown with "Installing..." message and a spinner.
* * <p/>
* (3) A staging folder, $STAGING_PREFIX, is {@link #deleteFolder(File)} if left over from broken installation below. * (3) A staging folder, $STAGING_PREFIX, is {@link #deleteFolder(File)} if left over from broken installation below.
* * <p/>
* (4) The architecture is determined and an appropriate bootstrap zip url is determined in {@link #determineZipUrl()}. * (4) The architecture is determined and an appropriate bootstrap zip url is determined in {@link #determineZipUrl()}.
* * <p/>
* (5) The zip, containing entries relative to the $PREFIX, is is downloaded and extracted by a zip input stream * (5) The zip, containing entries relative to the $PREFIX, is is downloaded and extracted by a zip input stream
* continously encountering zip file entries: * continously encountering zip file entries:
* * <p/>
* (5.1) If the zip entry encountered is SYMLINKS.txt, go through it and remember all symlinks to setup. * (5.1) If the zip entry encountered is SYMLINKS.txt, go through it and remember all symlinks to setup.
* * <p/>
* (5.2) For every other zip entry, extract it into $STAGING_PREFIX and set execute permissions if necessary. * (5.2) For every other zip entry, extract it into $STAGING_PREFIX and set execute permissions if necessary.
*/ */
final class TermuxInstaller { final class TermuxInstaller {
@@ -97,7 +97,8 @@ final class TermuxInstaller {
String line; String line;
while ((line = symlinksReader.readLine()) != null) { while ((line = symlinksReader.readLine()) != null) {
String[] parts = line.split(""); String[] parts = line.split("");
if (parts.length != 2) throw new RuntimeException("Malformed symlink line: " + line); if (parts.length != 2)
throw new RuntimeException("Malformed symlink line: " + line);
String oldPath = parts[0]; String oldPath = parts[0];
String newPath = STAGING_PREFIX_PATH + "/" + parts[1]; String newPath = STAGING_PREFIX_PATH + "/" + parts[1];
symlinks.add(Pair.create(oldPath, newPath)); symlinks.add(Pair.create(oldPath, newPath));
@@ -106,7 +107,8 @@ final class TermuxInstaller {
String zipEntryName = zipEntry.getName(); String zipEntryName = zipEntry.getName();
File targetFile = new File(STAGING_PREFIX_PATH, zipEntryName); File targetFile = new File(STAGING_PREFIX_PATH, zipEntryName);
if (zipEntry.isDirectory()) { if (zipEntry.isDirectory()) {
if (!targetFile.mkdirs()) throw new RuntimeException("Failed to create directory: " + targetFile.getAbsolutePath()); if (!targetFile.mkdirs())
throw new RuntimeException("Failed to create directory: " + targetFile.getAbsolutePath());
} else { } else {
try (FileOutputStream outStream = new FileOutputStream(targetFile)) { try (FileOutputStream outStream = new FileOutputStream(targetFile)) {
int readBytes; int readBytes;
@@ -122,7 +124,8 @@ final class TermuxInstaller {
} }
} }
if (symlinks.isEmpty()) throw new RuntimeException("No SYMLINKS.txt encountered"); if (symlinks.isEmpty())
throw new RuntimeException("No SYMLINKS.txt encountered");
for (Pair<String, String> symlink : symlinks) { for (Pair<String, String> symlink : symlinks) {
Os.symlink(symlink.first, symlink.second); Os.symlink(symlink.first, symlink.second);
} }

View File

@@ -111,7 +111,8 @@ public final class TermuxKeyListener implements TerminalKeyListener {
mActivity.changeFontSize(false); mActivity.changeFontSize(false);
} else if (unicodeChar >= '1' && unicodeChar <= '9') { } else if (unicodeChar >= '1' && unicodeChar <= '9') {
int num = unicodeChar - '1'; int num = unicodeChar - '1';
if (service.getSessions().size() > num) mActivity.switchToSession(service.getSessions().get(num)); if (service.getSessions().size() > num)
mActivity.switchToSession(service.getSessions().get(num));
} }
return true; return true;
} }

View File

@@ -22,7 +22,8 @@ final class TermuxPreferences {
@IntDef({BELL_VIBRATE, BELL_BEEP, BELL_IGNORE}) @IntDef({BELL_VIBRATE, BELL_BEEP, BELL_IGNORE})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface AsciiBellBehaviour {} public @interface AsciiBellBehaviour {
}
static final int BELL_VIBRATE = 1; static final int BELL_VIBRATE = 1;
static final int BELL_BEEP = 2; static final int BELL_BEEP = 2;
@@ -127,7 +128,8 @@ final class TermuxPreferences {
public void reloadFromProperties(Context context) { public void reloadFromProperties(Context context) {
try { try {
File propsFile = new File(TermuxService.HOME_PATH + "/.termux/termux.properties"); File propsFile = new File(TermuxService.HOME_PATH + "/.termux/termux.properties");
if (!propsFile.exists()) propsFile = new File(TermuxService.HOME_PATH + "/.config/termux/termux.properties"); if (!propsFile.exists())
propsFile = new File(TermuxService.HOME_PATH + "/.config/termux/termux.properties");
Properties props = new Properties(); Properties props = new Properties();
if (propsFile.isFile() && propsFile.canRead()) { if (propsFile.isFile() && propsFile.canRead()) {

View File

@@ -1,15 +1,5 @@
package com.termux.app; package com.termux.app;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.termux.R;
import com.termux.terminal.EmulatorDebug;
import com.termux.terminal.TerminalSession;
import com.termux.terminal.TerminalSession.SessionChangedCallback;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
@@ -26,15 +16,25 @@ import android.os.PowerManager;
import android.util.Log; import android.util.Log;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import com.termux.R;
import com.termux.terminal.EmulatorDebug;
import com.termux.terminal.TerminalSession;
import com.termux.terminal.TerminalSession.SessionChangedCallback;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/** /**
* A service holding a list of terminal sessions, {@link #mTerminalSessions}, showing a foreground notification while * A service holding a list of terminal sessions, {@link #mTerminalSessions}, showing a foreground notification while
* running so that it is not terminated. The user interacts with the session through {@link TermuxActivity}, but this * running so that it is not terminated. The user interacts with the session through {@link TermuxActivity}, but this
* service may outlive the activity when the user or the system disposes of the activity. In that case the user may * service may outlive the activity when the user or the system disposes of the activity. In that case the user may
* restart {@link TermuxActivity} later to yet again access the sessions. * restart {@link TermuxActivity} later to yet again access the sessions.
* * <p/>
* In order to keep both terminal sessions and spawned processes (who may outlive the terminal sessions) alive as long * In order to keep both terminal sessions and spawned processes (who may outlive the terminal sessions) alive as long
* as wanted by the user this service is a foreground service, {@link Service#startForeground(int, Notification)}. * as wanted by the user this service is a foreground service, {@link Service#startForeground(int, Notification)}.
* * <p/>
* Optionally may hold a wake and a wifi lock, in which case that is shown in the notification - see * Optionally may hold a wake and a wifi lock, in which case that is shown in the notification - see
* {@link #buildNotification()}. * {@link #buildNotification()}.
*/ */
@@ -70,7 +70,7 @@ public final class TermuxService extends Service implements SessionChangedCallba
/** /**
* The terminal sessions which this service manages. * The terminal sessions which this service manages.
* * <p/>
* Note that this list is observed by {@link TermuxActivity#mListViewAdapter}, so any changes must be made on the UI * Note that this list is observed by {@link TermuxActivity#mListViewAdapter}, so any changes must be made on the UI
* thread and followed by a call to {@link ArrayAdapter#notifyDataSetChanged()} }. * thread and followed by a call to {@link ArrayAdapter#notifyDataSetChanged()} }.
*/ */
@@ -248,7 +248,7 @@ public final class TermuxService extends Service implements SessionChangedCallba
if (failSafe) { if (failSafe) {
// Keep the default path so that system binaries can be used in the failsafe session. // Keep the default path so that system binaries can be used in the failsafe session.
final String pathEnv = "PATH=" + System.getenv("PATH"); final String pathEnv = "PATH=" + System.getenv("PATH");
env = new String[] { termEnv, homeEnv, prefixEnv, androidRootEnv, androidDataEnv, pathEnv, externalStorageEnv }; env = new String[]{termEnv, homeEnv, prefixEnv, androidRootEnv, androidDataEnv, pathEnv, externalStorageEnv};
} else { } else {
final String ps1Env = "PS1=$ "; final String ps1Env = "PS1=$ ";
final String ldEnv = "LD_LIBRARY_PATH=" + PREFIX_PATH + "/lib"; final String ldEnv = "LD_LIBRARY_PATH=" + PREFIX_PATH + "/lib";
@@ -256,7 +256,7 @@ public final class TermuxService extends Service implements SessionChangedCallba
final String pathEnv = "PATH=" + PREFIX_PATH + "/bin:" + PREFIX_PATH + "/bin/applets"; final String pathEnv = "PATH=" + PREFIX_PATH + "/bin:" + PREFIX_PATH + "/bin/applets";
final String pwdEnv = "PWD=" + cwd; final String pwdEnv = "PWD=" + cwd;
env = new String[] { termEnv, homeEnv, prefixEnv, ps1Env, ldEnv, langEnv, pathEnv, pwdEnv, androidRootEnv, androidDataEnv, externalStorageEnv }; env = new String[]{termEnv, homeEnv, prefixEnv, ps1Env, ldEnv, langEnv, pathEnv, pwdEnv, androidRootEnv, androidDataEnv, externalStorageEnv};
} }
String shellName; String shellName;
@@ -277,7 +277,7 @@ public final class TermuxService extends Service implements SessionChangedCallba
if (executablePath == null) { if (executablePath == null) {
// Try bash, zsh and ash in that order: // Try bash, zsh and ash in that order:
for (String shellBinary : new String[] { "bash", "zsh", "ash" }) { for (String shellBinary : new String[]{"bash", "zsh", "ash"}) {
File shellFile = new File(PREFIX_PATH + "/bin/" + shellBinary); File shellFile = new File(PREFIX_PATH + "/bin/" + shellBinary);
if (shellFile.canExecute()) { if (shellFile.canExecute()) {
executablePath = shellFile.getAbsolutePath(); executablePath = shellFile.getAbsolutePath();
@@ -300,7 +300,7 @@ public final class TermuxService extends Service implements SessionChangedCallba
String[] args; String[] args;
if (arguments == null) { if (arguments == null) {
args = new String[] { shellName }; args = new String[]{shellName};
} else { } else {
args = new String[arguments.length + 1]; args = new String[arguments.length + 1];
args[0] = shellName; args[0] = shellName;
@@ -334,7 +334,8 @@ public final class TermuxService extends Service implements SessionChangedCallba
@Override @Override
public void onSessionFinished(final TerminalSession finishedSession) { public void onSessionFinished(final TerminalSession finishedSession) {
if (mSessionChangeCallback != null) mSessionChangeCallback.onSessionFinished(finishedSession); if (mSessionChangeCallback != null)
mSessionChangeCallback.onSessionFinished(finishedSession);
} }
@Override @Override

View File

@@ -23,9 +23,9 @@ import java.util.LinkedList;
/** /**
* A document provider for the Storage Access Framework which exposes the files in the * A document provider for the Storage Access Framework which exposes the files in the
* $HOME/ folder to other apps. * $HOME/ folder to other apps.
* <p> * <p/>
* Note that this replaces providing an activity matching the ACTION_GET_CONTENT intent: * Note that this replaces providing an activity matching the ACTION_GET_CONTENT intent:
* <p> * <p/>
* "A document provider and ACTION_GET_CONTENT should be considered mutually exclusive. If you * "A document provider and ACTION_GET_CONTENT should be considered mutually exclusive. If you
* support both of them simultaneously, your app will appear twice in the system picker UI, * support both of them simultaneously, your app will appear twice in the system picker UI,
* offering two different ways of accessing your stored data. This would be confusing for users." * offering two different ways of accessing your stored data. This would be confusing for users."
@@ -172,7 +172,7 @@ public class TermuxDocumentsProvider extends DocumentsProvider {
/** /**
* Get the document id given a file. This document id must be consistent across time as other * Get the document id given a file. This document id must be consistent across time as other
* applications may save the ID and use it to reference documents later. * applications may save the ID and use it to reference documents later.
* <p> * <p/>
* The reverse of @{link #getFileForDocId}. * The reverse of @{link #getFileForDocId}.
*/ */
private static String getDocIdForFile(File file) { private static String getDocIdForFile(File file) {

View File

@@ -53,7 +53,7 @@ final class ByteQueue {
/** /**
* Attempt to write the specified portion of the provided buffer to the queue. * Attempt to write the specified portion of the provided buffer to the queue.
* * <p/>
* Returns whether the output was totally written, false if it was closed before. * Returns whether the output was totally written, false if it was closed before.
*/ */
public boolean write(byte[] buffer, int offset, int lengthToWrite) { public boolean write(byte[] buffer, int offset, int lengthToWrite) {

View File

@@ -12,19 +12,14 @@ final class JNI {
/** /**
* Create a subprocess. Differs from {@link ProcessBuilder} in that a pseudoterminal is used to communicate with the * Create a subprocess. Differs from {@link ProcessBuilder} in that a pseudoterminal is used to communicate with the
* subprocess. * subprocess.
* * <p/>
* Callers are responsible for calling {@link #close(int)} on the returned file descriptor. * Callers are responsible for calling {@link #close(int)} on the returned file descriptor.
* *
* @param cmd * @param cmd The command to execute
* The command to execute * @param cwd The current working directory for the executed command
* @param cwd * @param args An array of arguments to the command
* The current working directory for the executed command * @param envVars An array of strings of the form "VAR=value" to be added to the environment of the process
* @param args * @param processId A one-element array to which the process ID of the started process will be written.
* An array of arguments to the command
* @param envVars
* An array of strings of the form "VAR=value" to be added to the environment of the process
* @param processId
* A one-element array to which the process ID of the started process will be written.
* @return the file descriptor resulting from opening /dev/ptmx master device. The sub process will have opened the * @return the file descriptor resulting from opening /dev/ptmx master device. The sub process will have opened the
* slave device counterpart (/dev/pts/$N) and have it as stdint, stdout and stderr. * slave device counterpart (/dev/pts/$N) and have it as stdint, stdout and stderr.
*/ */

View File

@@ -1,5 +1,10 @@
package com.termux.terminal; package com.termux.terminal;
import android.view.KeyEvent;
import java.util.HashMap;
import java.util.Map;
import static android.view.KeyEvent.KEYCODE_BREAK; import static android.view.KeyEvent.KEYCODE_BREAK;
import static android.view.KeyEvent.KEYCODE_DEL; import static android.view.KeyEvent.KEYCODE_DEL;
import static android.view.KeyEvent.KEYCODE_DPAD_CENTER; import static android.view.KeyEvent.KEYCODE_DPAD_CENTER;
@@ -22,6 +27,7 @@ import static android.view.KeyEvent.KEYCODE_F7;
import static android.view.KeyEvent.KEYCODE_F8; import static android.view.KeyEvent.KEYCODE_F8;
import static android.view.KeyEvent.KEYCODE_F9; import static android.view.KeyEvent.KEYCODE_F9;
import static android.view.KeyEvent.KEYCODE_FORWARD_DEL; import static android.view.KeyEvent.KEYCODE_FORWARD_DEL;
import static android.view.KeyEvent.KEYCODE_HOME;
import static android.view.KeyEvent.KEYCODE_INSERT; import static android.view.KeyEvent.KEYCODE_INSERT;
import static android.view.KeyEvent.KEYCODE_MOVE_END; import static android.view.KeyEvent.KEYCODE_MOVE_END;
import static android.view.KeyEvent.KEYCODE_NUMPAD_0; import static android.view.KeyEvent.KEYCODE_NUMPAD_0;
@@ -47,12 +53,6 @@ import static android.view.KeyEvent.KEYCODE_PAGE_DOWN;
import static android.view.KeyEvent.KEYCODE_PAGE_UP; import static android.view.KeyEvent.KEYCODE_PAGE_UP;
import static android.view.KeyEvent.KEYCODE_SYSRQ; import static android.view.KeyEvent.KEYCODE_SYSRQ;
import static android.view.KeyEvent.KEYCODE_TAB; import static android.view.KeyEvent.KEYCODE_TAB;
import static android.view.KeyEvent.KEYCODE_HOME;
import java.util.HashMap;
import java.util.Map;
import android.view.KeyEvent;
public final class KeyHandler { public final class KeyHandler {
@@ -61,6 +61,7 @@ public final class KeyHandler {
public static final int KEYMOD_SHIFT = 0x20000000; public static final int KEYMOD_SHIFT = 0x20000000;
private static final Map<String, Integer> TERMCAP_TO_KEYCODE = new HashMap<>(); private static final Map<String, Integer> TERMCAP_TO_KEYCODE = new HashMap<>();
static { static {
// terminfo: http://pubs.opengroup.org/onlinepubs/7990989799/xcurses/terminfo.html // terminfo: http://pubs.opengroup.org/onlinepubs/7990989799/xcurses/terminfo.html
// termcap: http://man7.org/linux/man-pages/man5/termcap.5.html // termcap: http://man7.org/linux/man-pages/man5/termcap.5.html

View File

@@ -3,7 +3,7 @@ package com.termux.terminal;
/** /**
* A circular buffer of {@link TerminalRow}:s which keeps notes about what is visible on a logical screen and the scroll * A circular buffer of {@link TerminalRow}:s which keeps notes about what is visible on a logical screen and the scroll
* history. * history.
* * <p/>
* See {@link #externalToInternalRow(int)} for how to map from logical screen rows to array indices. * See {@link #externalToInternalRow(int)} for how to map from logical screen rows to array indices.
*/ */
public final class TerminalBuffer { public final class TerminalBuffer {
@@ -21,12 +21,9 @@ public final class TerminalBuffer {
/** /**
* Create a transcript screen. * Create a transcript screen.
* *
* @param columns * @param columns the width of the screen in characters.
* the width of the screen in characters. * @param totalRows the height of the entire text area, in rows of text.
* @param totalRows * @param screenRows the height of just the screen, not including the transcript that holds lines that have scrolled off
* the height of the entire text area, in rows of text.
* @param screenRows
* the height of just the screen, not including the transcript that holds lines that have scrolled off
* the top of the screen. * the top of the screen.
*/ */
public TerminalBuffer(int columns, int totalRows, int screenRows) { public TerminalBuffer(int columns, int totalRows, int screenRows) {
@@ -63,7 +60,7 @@ public final class TerminalBuffer {
int x2Index = (x2 < mColumns) ? lineObject.findStartOfColumn(x2) : lineObject.getSpaceUsed(); int x2Index = (x2 < mColumns) ? lineObject.findStartOfColumn(x2) : lineObject.getSpaceUsed();
if (x2Index == x1Index) { if (x2Index == x1Index) {
// Selected the start of a wide character. // Selected the start of a wide character.
x2Index = lineObject.findStartOfColumn(x2+1); x2Index = lineObject.findStartOfColumn(x2 + 1);
} }
char[] line = lineObject.mText; char[] line = lineObject.mText;
int lastPrintingCharIndex = -1; int lastPrintingCharIndex = -1;
@@ -78,7 +75,8 @@ public final class TerminalBuffer {
if (c != ' ') lastPrintingCharIndex = i; if (c != ' ') lastPrintingCharIndex = i;
} }
} }
if (lastPrintingCharIndex != -1) builder.append(line, x1Index, lastPrintingCharIndex - x1Index + 1); if (lastPrintingCharIndex != -1)
builder.append(line, x1Index, lastPrintingCharIndex - x1Index + 1);
if (!rowLineWrap && row < selY2 && row < mScreenRows - 1) builder.append('\n'); if (!rowLineWrap && row < selY2 && row < mScreenRows - 1) builder.append('\n');
} }
return builder.toString(); return builder.toString();
@@ -94,15 +92,15 @@ public final class TerminalBuffer {
/** /**
* Convert a row value from the public external coordinate system to our internal private coordinate system. * Convert a row value from the public external coordinate system to our internal private coordinate system.
* * <p/>
* <ul> * <ul>
* <li>External coordinate system: -mActiveTranscriptRows to mScreenRows-1, with the screen being 0..mScreenRows-1. * <li>External coordinate system: -mActiveTranscriptRows to mScreenRows-1, with the screen being 0..mScreenRows-1.
* <li>Internal coordinate system: the mScreenRows lines starting at mScreenFirstRow comprise the screen, while the * <li>Internal coordinate system: the mScreenRows lines starting at mScreenFirstRow comprise the screen, while the
* mActiveTranscriptRows lines ending at mScreenFirstRow-1 form the transcript (as a circular buffer). * mActiveTranscriptRows lines ending at mScreenFirstRow-1 form the transcript (as a circular buffer).
* </ul> * </ul>
* * <p/>
* External <---> Internal: * External <---> Internal:
* * <p/>
* <pre> * <pre>
* [ ... ] [ ... ] * [ ... ] [ ... ]
* [ -mActiveTranscriptRows ] [ mScreenFirstRow - mActiveTranscriptRows ] * [ -mActiveTranscriptRows ] [ mScreenFirstRow - mActiveTranscriptRows ]
@@ -112,8 +110,7 @@ public final class TerminalBuffer {
* [ mScreenRows-1 ] [ mScreenFirstRow + mScreenRows-1 ] * [ mScreenRows-1 ] [ mScreenFirstRow + mScreenRows-1 ]
* </pre> * </pre>
* *
* @param externalRow * @param externalRow a row in the external coordinate system.
* a row in the external coordinate system.
* @return The row corresponding to the input argument in the private coordinate system. * @return The row corresponding to the input argument in the private coordinate system.
*/ */
public int externalToInternalRow(int externalRow) { public int externalToInternalRow(int externalRow) {
@@ -139,12 +136,9 @@ public final class TerminalBuffer {
* Resize the screen which this transcript backs. Currently, this only works if the number of columns does not * Resize the screen which this transcript backs. Currently, this only works if the number of columns does not
* change or the rows expand (that is, it only works when shrinking the number of rows). * change or the rows expand (that is, it only works when shrinking the number of rows).
* *
* @param newColumns * @param newColumns The number of columns the screen should have.
* The number of columns the screen should have. * @param newRows The number of rows the screen should have.
* @param newRows * @param cursor An int[2] containing the (column, row) cursor location.
* The number of rows the screen should have.
* @param cursor
* An int[2] containing the (column, row) cursor location.
*/ */
public void resize(int newColumns, int newRows, int newTotalRows, int[] cursor, int currentStyle, boolean altScreen) { public void resize(int newColumns, int newRows, int newTotalRows, int[] cursor, int currentStyle, boolean altScreen) {
// newRows > mTotalRows should not normally happen since mTotalRows is TRANSCRIPT_ROWS (10000): // newRows > mTotalRows should not normally happen since mTotalRows is TRANSCRIPT_ROWS (10000):
@@ -238,7 +232,8 @@ public final class TerminalBuffer {
} else { } else {
for (int i = 0; i < oldLine.getSpaceUsed(); i++) for (int i = 0; i < oldLine.getSpaceUsed(); i++)
// NEWLY INTRODUCED BUG! Should not index oldLine.mStyle with char indices // NEWLY INTRODUCED BUG! Should not index oldLine.mStyle with char indices
if (oldLine.mText[i] != ' '/* || oldLine.mStyle[i] != currentStyle */) lastNonSpaceIndex = i + 1; if (oldLine.mText[i] != ' '/* || oldLine.mStyle[i] != currentStyle */)
lastNonSpaceIndex = i + 1;
} }
int currentOldCol = 0; int currentOldCol = 0;
@@ -302,10 +297,8 @@ public final class TerminalBuffer {
* Block copy lines and associated metadata from one location to another in the circular buffer, taking wraparound * Block copy lines and associated metadata from one location to another in the circular buffer, taking wraparound
* into account. * into account.
* *
* @param srcInternal * @param srcInternal The first line to be copied.
* The first line to be copied. * @param len The number of lines to be copied.
* @param len
* The number of lines to be copied.
*/ */
private void blockCopyLinesDown(int srcInternal, int len) { private void blockCopyLinesDown(int srcInternal, int len) {
if (len == 0) return; if (len == 0) return;
@@ -324,12 +317,9 @@ public final class TerminalBuffer {
/** /**
* Scroll the screen down one line. To scroll the whole screen of a 24 line screen, the arguments would be (0, 24). * Scroll the screen down one line. To scroll the whole screen of a 24 line screen, the arguments would be (0, 24).
* *
* @param topMargin * @param topMargin First line that is scrolled.
* First line that is scrolled. * @param bottomMargin One line after the last line that is scrolled.
* @param bottomMargin * @param style the style for the newly exposed line.
* One line after the last line that is scrolled.
* @param style
* the style for the newly exposed line.
*/ */
public void scrollDownOneLine(int topMargin, int bottomMargin, int style) { public void scrollDownOneLine(int topMargin, int bottomMargin, int style) {
if (topMargin > bottomMargin - 1 || topMargin < 0 || bottomMargin > mScreenRows) if (topMargin > bottomMargin - 1 || topMargin < 0 || bottomMargin > mScreenRows)
@@ -360,18 +350,12 @@ public final class TerminalBuffer {
* of the source and destination must be within the bounds of the screen, or else an InvalidParameterException will * of the source and destination must be within the bounds of the screen, or else an InvalidParameterException will
* be thrown. * be thrown.
* *
* @param sx * @param sx source X coordinate
* source X coordinate * @param sy source Y coordinate
* @param sy * @param w width
* source Y coordinate * @param h height
* @param w * @param dx destination X coordinate
* width * @param dy destination Y coordinate
* @param h
* height
* @param dx
* destination X coordinate
* @param dy
* destination Y coordinate
*/ */
public void blockCopy(int sx, int sy, int w, int h, int dx, int dy) { public void blockCopy(int sx, int sy, int w, int h, int dx, int dy) {
if (w == 0) return; if (w == 0) return;

View File

@@ -57,7 +57,7 @@ public final class TerminalColorScheme {
0xff808080, 0xff8a8a8a, 0xff949494, 0xff9e9e9e, 0xffa8a8a8, 0xffb2b2b2, 0xffbcbcbc, 0xffc6c6c6, 0xffd0d0d0, 0xffdadada, 0xffe4e4e4, 0xffeeeeee, 0xff808080, 0xff8a8a8a, 0xff949494, 0xff9e9e9e, 0xffa8a8a8, 0xffb2b2b2, 0xffbcbcbc, 0xffc6c6c6, 0xffd0d0d0, 0xffdadada, 0xffe4e4e4, 0xffeeeeee,
// COLOR_INDEX_DEFAULT_FOREGROUND, COLOR_INDEX_DEFAULT_BACKGROUND and COLOR_INDEX_DEFAULT_CURSOR: // COLOR_INDEX_DEFAULT_FOREGROUND, COLOR_INDEX_DEFAULT_BACKGROUND and COLOR_INDEX_DEFAULT_CURSOR:
0xffffffff, 0xff000000, 0xffffffff }; 0xffffffff, 0xff000000, 0xffffffff};
public final int[] mDefaultColors = new int[TextStyle.NUM_INDEXED_COLORS]; public final int[] mDefaultColors = new int[TextStyle.NUM_INDEXED_COLORS];
@@ -93,7 +93,8 @@ public final class TerminalColorScheme {
} }
int colorValue = TerminalColors.parse(value); int colorValue = TerminalColors.parse(value);
if (colorValue == 0) throw new IllegalArgumentException("Property '" + key + "' has invalid color: '" + value + "'"); if (colorValue == 0)
throw new IllegalArgumentException("Property '" + key + "' has invalid color: '" + value + "'");
mDefaultColors[colorIndex] = colorValue; mDefaultColors[colorIndex] = colorValue;
} }

View File

@@ -29,7 +29,7 @@ public final class TerminalColors {
/** /**
* Parse color according to http://manpages.ubuntu.com/manpages/intrepid/man3/XQueryColor.3.html * Parse color according to http://manpages.ubuntu.com/manpages/intrepid/man3/XQueryColor.3.html
* * <p/>
* Highest bit is set if successful, so return value is 0xFF${R}${G}${B}. Return 0 if failed. * Highest bit is set if successful, so return value is 0xFF${R}${G}${B}. Return 0 if failed.
*/ */
static int parse(String c) { static int parse(String c) {

View File

@@ -1,18 +1,18 @@
package com.termux.terminal; package com.termux.terminal;
import android.util.Base64;
import android.util.Log;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.Stack; import java.util.Stack;
import android.util.Base64;
import android.util.Log;
/** /**
* Renders text into a screen. Contains all the terminal-specific knowledge and state. Emulates a subset of the X Window * Renders text into a screen. Contains all the terminal-specific knowledge and state. Emulates a subset of the X Window
* System xterm terminal, which in turn is an emulator for a subset of the Digital Equipment Corporation vt100 terminal. * System xterm terminal, which in turn is an emulator for a subset of the Digital Equipment Corporation vt100 terminal.
* * <p/>
* References: * References:
* <ul> * <ul>
* <li>http://invisible-island.net/xterm/ctlseqs/ctlseqs.html</li> * <li>http://invisible-island.net/xterm/ctlseqs/ctlseqs.html</li>
@@ -145,7 +145,7 @@ public final class TerminalEmulator {
/** /**
* The alternate screen buffer, exactly as large as the display and contains no additional saved lines (so that when * The alternate screen buffer, exactly as large as the display and contains no additional saved lines (so that when
* the alternate screen buffer is active, you cannot scroll back to view saved lines). * the alternate screen buffer is active, you cannot scroll back to view saved lines).
* * <p/>
* See http://www.xfree86.org/current/ctlseqs.html#The%20Alternate%20Screen%20Buffer * See http://www.xfree86.org/current/ctlseqs.html#The%20Alternate%20Screen%20Buffer
*/ */
final TerminalBuffer mAltBuffer; final TerminalBuffer mAltBuffer;
@@ -294,8 +294,7 @@ public final class TerminalEmulator {
} }
/** /**
* @param mouseButton * @param mouseButton one of the MOUSE_* constants of this class.
* one of the MOUSE_* constants of this class.
*/ */
public void sendMouseEvent(int mouseButton, int column, int row, boolean pressed) { public void sendMouseEvent(int mouseButton, int column, int row, boolean pressed) {
if (mouseButton == MOUSE_LEFT_BUTTON_MOVED && !isDecsetInternalBitSet(DECSET_BIT_MOUSE_TRACKING_BUTTON_EVENT)) { if (mouseButton == MOUSE_LEFT_BUTTON_MOVED && !isDecsetInternalBitSet(DECSET_BIT_MOUSE_TRACKING_BUTTON_EVENT)) {
@@ -307,7 +306,7 @@ public final class TerminalEmulator {
// Clip to screen, and clip to the limits of 8-bit data. // Clip to screen, and clip to the limits of 8-bit data.
boolean out_of_bounds = column < 1 || row < 1 || column > mColumns || row > mRows || column > 255 - 32 || row > 255 - 32; boolean out_of_bounds = column < 1 || row < 1 || column > mColumns || row > mRows || column > 255 - 32 || row > 255 - 32;
if (!out_of_bounds) { if (!out_of_bounds) {
byte[] data = { '\033', '[', 'M', (byte) (32 + mouseButton), (byte) (32 + column), (byte) (32 + row) }; byte[] data = {'\033', '[', 'M', (byte) (32 + mouseButton), (byte) (32 + column), (byte) (32 + row)};
mSession.write(data, 0, data.length); mSession.write(data, 0, data.length);
} }
} }
@@ -341,7 +340,7 @@ public final class TerminalEmulator {
} }
private void resizeScreen() { private void resizeScreen() {
final int[] cursor = { mCursorCol, mCursorRow }; final int[] cursor = {mCursorCol, mCursorRow};
int newTotalRows = (mScreen == mAltBuffer) ? mRows : mMainBuffer.mTotalRows; int newTotalRows = (mScreen == mAltBuffer) ? mRows : mMainBuffer.mTotalRows;
mScreen.resize(mColumns, mRows, newTotalRows, cursor, getStyle(), isAlternateBufferActive()); mScreen.resize(mColumns, mRows, newTotalRows, cursor, getStyle(), isAlternateBufferActive());
mCursorCol = cursor[0]; mCursorCol = cursor[0];
@@ -390,10 +389,8 @@ public final class TerminalEmulator {
/** /**
* Accept bytes (typically from the pseudo-teletype) and process them. * Accept bytes (typically from the pseudo-teletype) and process them.
* *
* @param buffer * @param buffer a byte array containing the bytes to be processed
* a byte array containing the bytes to be processed * @param length the number of bytes in the array to process
* @param length
* the number of bytes in the array to process
*/ */
public void append(byte[] buffer, int length) { public void append(byte[] buffer, int length) {
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
@@ -897,7 +894,8 @@ public final class TerminalEmulator {
} }
} }
} else { } else {
if (LOG_ESCAPE_SEQUENCES) Log.e(EmulatorDebug.LOG_TAG, "Unrecognized device control string: " + dcs); if (LOG_ESCAPE_SEQUENCES)
Log.e(EmulatorDebug.LOG_TAG, "Unrecognized device control string: " + dcs);
} }
finishSequence(); finishSequence();
} }
@@ -1086,7 +1084,8 @@ public final class TerminalEmulator {
// Check if buffer size needs to be updated: // Check if buffer size needs to be updated:
if (resized) resizeScreen(); if (resized) resizeScreen();
// Clear new screen if alt buffer: // Clear new screen if alt buffer:
if (newScreen == mAltBuffer) newScreen.blockSet(0, 0, mColumns, mRows, ' ', getStyle()); if (newScreen == mAltBuffer)
newScreen.blockSet(0, 0, mColumns, mRows, ' ', getStyle());
} }
break; break;
} }
@@ -1542,7 +1541,7 @@ public final class TerminalEmulator {
switch (getArg0(0)) { switch (getArg0(0)) {
case 5: // Device status report (DSR): case 5: // Device status report (DSR):
// Answer is ESC [ 0 n (Terminal OK). // Answer is ESC [ 0 n (Terminal OK).
byte[] dsr = { (byte) 27, (byte) '[', (byte) '0', (byte) 'n' }; byte[] dsr = {(byte) 27, (byte) '[', (byte) '0', (byte) 'n'};
mSession.write(dsr, 0, dsr.length); mSession.write(dsr, 0, dsr.length);
break; break;
case 6: // Cursor position report (CPR): case 6: // Cursor position report (CPR):
@@ -1721,7 +1720,8 @@ public final class TerminalEmulator {
mBackColor = color; mBackColor = color;
} }
} else { } else {
if (LOG_ESCAPE_SEQUENCES) Log.w(EmulatorDebug.LOG_TAG, "Invalid color index: " + color); if (LOG_ESCAPE_SEQUENCES)
Log.w(EmulatorDebug.LOG_TAG, "Invalid color index: " + color);
} }
} }
} }
@@ -1736,7 +1736,8 @@ public final class TerminalEmulator {
} else if (code >= 100 && code <= 107) { // Bright background color (aixterm codes). } else if (code >= 100 && code <= 107) { // Bright background color (aixterm codes).
mBackColor = code - 100 + 8; mBackColor = code - 100 + 8;
} else { } else {
if (LOG_ESCAPE_SEQUENCES) Log.w(EmulatorDebug.LOG_TAG, String.format("SGR unknown code %d", code)); if (LOG_ESCAPE_SEQUENCES)
Log.w(EmulatorDebug.LOG_TAG, String.format("SGR unknown code %d", code));
} }
} }
} }
@@ -1804,7 +1805,7 @@ public final class TerminalEmulator {
// and specification can be given in one control sequence, xterm can make more than one reply. // and specification can be given in one control sequence, xterm can make more than one reply.
int colorIndex = -1; int colorIndex = -1;
int parsingPairStart = -1; int parsingPairStart = -1;
for (int i = 0;; i++) { for (int i = 0; ; i++) {
boolean endOfInput = i == textParameter.length(); boolean endOfInput = i == textParameter.length();
char b = endOfInput ? ';' : textParameter.charAt(i); char b = endOfInput ? ';' : textParameter.charAt(i);
if (b == ';') { if (b == ';') {
@@ -1837,7 +1838,7 @@ public final class TerminalEmulator {
case 12: // Set cursor color. case 12: // Set cursor color.
int specialIndex = TextStyle.COLOR_INDEX_FOREGROUND + (value - 10); int specialIndex = TextStyle.COLOR_INDEX_FOREGROUND + (value - 10);
int lastSemiIndex = 0; int lastSemiIndex = 0;
for (int charIndex = 0;; charIndex++) { for (int charIndex = 0; ; charIndex++) {
boolean endOfInput = charIndex == textParameter.length(); boolean endOfInput = charIndex == textParameter.length();
if (endOfInput || textParameter.charAt(charIndex) == ';') { if (endOfInput || textParameter.charAt(charIndex) == ';') {
try { try {
@@ -1855,7 +1856,8 @@ public final class TerminalEmulator {
mSession.onColorsChanged(); mSession.onColorsChanged();
} }
specialIndex++; specialIndex++;
if (endOfInput || (specialIndex > TextStyle.COLOR_INDEX_CURSOR) || ++charIndex >= textParameter.length()) break; if (endOfInput || (specialIndex > TextStyle.COLOR_INDEX_CURSOR) || ++charIndex >= textParameter.length())
break;
lastSemiIndex = charIndex; lastSemiIndex = charIndex;
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
// Ignore. // Ignore.
@@ -1882,7 +1884,7 @@ public final class TerminalEmulator {
mSession.onColorsChanged(); mSession.onColorsChanged();
} else { } else {
int lastIndex = 0; int lastIndex = 0;
for (int charIndex = 0;; charIndex++) { for (int charIndex = 0; ; charIndex++) {
boolean endOfInput = charIndex == textParameter.length(); boolean endOfInput = charIndex == textParameter.length();
if (endOfInput || textParameter.charAt(charIndex) == ';') { if (endOfInput || textParameter.charAt(charIndex) == ';') {
try { try {
@@ -2075,8 +2077,7 @@ public final class TerminalEmulator {
/** /**
* Send a Unicode code point to the screen. * Send a Unicode code point to the screen.
* *
* @param codePoint * @param codePoint The code point of the character to display
* The code point of the character to display
*/ */
private void emitCodePoint(int codePoint) { private void emitCodePoint(int codePoint) {
if (mUseLineDrawingUsesG0 ? mUseLineDrawingG0 : mUseLineDrawingG1) { if (mUseLineDrawingUsesG0 ? mUseLineDrawingG0 : mUseLineDrawingG1) {
@@ -2207,13 +2208,15 @@ public final class TerminalEmulator {
if (mInsertMode && displayWidth > 0) { if (mInsertMode && displayWidth > 0) {
// Move character to right one space. // Move character to right one space.
int destCol = mCursorCol + displayWidth; int destCol = mCursorCol + displayWidth;
if (destCol < mRightMargin) mScreen.blockCopy(mCursorCol, mCursorRow, mRightMargin - destCol, 1, destCol, mCursorRow); if (destCol < mRightMargin)
mScreen.blockCopy(mCursorCol, mCursorRow, mRightMargin - destCol, 1, destCol, mCursorRow);
} }
int offsetDueToCombiningChar = ((displayWidth <= 0 && mCursorCol > 0 && !mAboutToAutoWrap) ? 1 : 0); int offsetDueToCombiningChar = ((displayWidth <= 0 && mCursorCol > 0 && !mAboutToAutoWrap) ? 1 : 0);
mScreen.setChar(mCursorCol - offsetDueToCombiningChar, mCursorRow, codePoint, getStyle()); mScreen.setChar(mCursorCol - offsetDueToCombiningChar, mCursorRow, codePoint, getStyle());
if (autoWrap && displayWidth > 0) mAboutToAutoWrap = (mCursorCol == mRightMargin - displayWidth); if (autoWrap && displayWidth > 0)
mAboutToAutoWrap = (mCursorCol == mRightMargin - displayWidth);
mCursorCol = Math.min(mCursorCol + displayWidth, mRightMargin - 1); mCursorCol = Math.min(mCursorCol + displayWidth, mRightMargin - 1);
} }

View File

@@ -4,7 +4,7 @@ import java.util.Arrays;
/** /**
* A row in a terminal, composed of a fixed number of cells. * A row in a terminal, composed of a fixed number of cells.
* * <p/>
* The text in the row is stored in a char[] array, {@link #mText}, for quick access during rendering. * The text in the row is stored in a char[] array, {@link #mText}, for quick access during rendering.
*/ */
public final class TerminalRow { public final class TerminalRow {
@@ -99,7 +99,7 @@ public final class TerminalRow {
} }
private boolean wideDisplayCharacterStartingAt(int column) { private boolean wideDisplayCharacterStartingAt(int column) {
for (int currentCharIndex = 0, currentColumn = 0; currentCharIndex < mSpaceUsed;) { for (int currentCharIndex = 0, currentColumn = 0; currentCharIndex < mSpaceUsed; ) {
char c = mText[currentCharIndex++]; char c = mText[currentCharIndex++];
int codePoint = Character.isHighSurrogate(c) ? Character.toCodePoint(c, mText[currentCharIndex++]) : c; int codePoint = Character.isHighSurrogate(c) ? Character.toCodePoint(c, mText[currentCharIndex++]) : c;
int wcwidth = WcWidth.width(codePoint); int wcwidth = WcWidth.width(codePoint);

View File

@@ -19,13 +19,13 @@ import java.util.UUID;
/** /**
* A terminal session, consisting of a process coupled to a terminal interface. * A terminal session, consisting of a process coupled to a terminal interface.
* <p> * <p/>
* The subprocess will be executed by the constructor, and when the size is made known by a call to * The subprocess will be executed by the constructor, and when the size is made known by a call to
* {@link #updateSize(int, int)} terminal emulation will begin and threads will be spawned to handle the subprocess I/O. * {@link #updateSize(int, int)} terminal emulation will begin and threads will be spawned to handle the subprocess I/O.
* All terminal emulation and callback methods will be performed on the main thread. * All terminal emulation and callback methods will be performed on the main thread.
* <p> * <p/>
* The child process may be exited forcefully by using the {@link #finishIfRunning()} method. * The child process may be exited forcefully by using the {@link #finishIfRunning()} method.
* * <p/>
* NOTE: The terminal session may outlive the EmulatorView, so be careful with callbacks! * NOTE: The terminal session may outlive the EmulatorView, so be careful with callbacks!
*/ */
public final class TerminalSession extends TerminalOutput { public final class TerminalSession extends TerminalOutput {
@@ -169,10 +169,8 @@ public final class TerminalSession extends TerminalOutput {
/** /**
* Set the terminal emulator's window size and start terminal emulation. * Set the terminal emulator's window size and start terminal emulation.
* *
* @param columns * @param columns The number of columns in the terminal window.
* The number of columns in the terminal window. * @param rows The number of rows in the terminal window.
* @param rows
* The number of rows in the terminal window.
*/ */
public void initializeEmulator(int columns, int rows) { public void initializeEmulator(int columns, int rows) {
mEmulator = new TerminalEmulator(this, columns, rows, /* transcript= */5000); mEmulator = new TerminalEmulator(this, columns, rows, /* transcript= */5000);
@@ -337,6 +335,8 @@ public final class TerminalSession extends TerminalOutput {
mChangeCallback.onColorsChanged(this); mChangeCallback.onColorsChanged(this);
} }
public int getPid() { return mShellPid; } public int getPid() {
return mShellPid;
}
} }

View File

@@ -3,7 +3,7 @@ package com.termux.terminal;
/** /**
* Encodes effects, foreground and background colors into a 32 bit integer, which are stored for each cell in a terminal * Encodes effects, foreground and background colors into a 32 bit integer, which are stored for each cell in a terminal
* row in {@link TerminalRow#mStyle}. * row in {@link TerminalRow#mStyle}.
* * <p/>
* The foreground and background colors take 9 bits each, leaving (32-9-9)=14 bits for effect flags. Using 9 for now * The foreground and background colors take 9 bits each, leaving (32-9-9)=14 bits for effect flags. Using 9 for now
* (the different CHARACTER_ATTRIBUTE_* bits). * (the different CHARACTER_ATTRIBUTE_* bits).
*/ */
@@ -18,7 +18,7 @@ public final class TextStyle {
public final static int CHARACTER_ATTRIBUTE_STRIKETHROUGH = 1 << 6; public final static int CHARACTER_ATTRIBUTE_STRIKETHROUGH = 1 << 6;
/** /**
* The selective erase control functions (DECSED and DECSEL) can only erase characters defined as erasable. * The selective erase control functions (DECSED and DECSEL) can only erase characters defined as erasable.
* * <p/>
* This bit is set if DECSCA (Select Character Protection Attribute) has been used to define the characters that * This bit is set if DECSCA (Select Character Protection Attribute) has been used to define the characters that
* come after it as erasable from the screen. * come after it as erasable from the screen.
*/ */

View File

@@ -2,12 +2,12 @@ package com.termux.terminal;
/** /**
* wcwidth() implementation from http://git.musl-libc.org/cgit/musl/tree/src/ctype * wcwidth() implementation from http://git.musl-libc.org/cgit/musl/tree/src/ctype
* * <p/>
* Modified to return 0 instead of -1. * Modified to return 0 instead of -1.
*/ */
public final class WcWidth { public final class WcWidth {
private static final short table[] = { 16, 16, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 16, 32, 16, 16, 16, 33, 34, 35, 36, 37, 38, private static final short table[] = {16, 16, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 16, 32, 16, 16, 16, 33, 34, 35, 36, 37, 38,
39, 16, 16, 40, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 41, 42, 16, 16, 43, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 39, 16, 16, 40, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 41, 42, 16, 16, 43, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
@@ -52,9 +52,9 @@ public final class WcWidth {
0, 0, 0, 0, 120, 38, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 128, 239, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 192, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 38, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 128, 239, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 192, 127, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 128, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 3, 248, 255, 231, 15, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 128, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 3, 248, 255, 231, 15, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
private static final short wtable[] = { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 18, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, private static final short wtable[] = {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 18, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 19, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 21, 22, 23, 24, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 19, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 21, 22, 23, 24, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 25, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 25, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
@@ -83,7 +83,7 @@ public final class WcWidth {
255, 255, 255, 255, 255, 15, 0, 0, 255, 3, 0, 0, 255, 255, 255, 255, 247, 255, 127, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 255, 255, 255, 15, 0, 0, 255, 3, 0, 0, 255, 255, 255, 255, 247, 255, 127, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 255, 255, 255, 255, 255, 7, 255, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 255, 255, 255, 255, 255, 7, 255, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0 }; 0, 0, 0, 0, 0, 0, 0, 0, 0};
/** Return the terminal display width of a code point: 0, 1 or 2. */ /** Return the terminal display width of a code point: 0, 1 or 2. */
public static int width(int wc) { public static int width(int wc) {

View File

@@ -9,7 +9,7 @@ import com.termux.terminal.TerminalSession;
/** /**
* Input and scale listener which may be set on a {@link TerminalView} through * Input and scale listener which may be set on a {@link TerminalView} through
* {@link TerminalView#setOnKeyListener(TerminalKeyListener)}. * {@link TerminalView#setOnKeyListener(TerminalKeyListener)}.
* * <p/>
* TODO: Rename to TerminalViewClient. * TODO: Rename to TerminalViewClient.
*/ */
public interface TerminalKeyListener { public interface TerminalKeyListener {

View File

@@ -13,7 +13,7 @@ import com.termux.terminal.WcWidth;
/** /**
* Renderer of a {@link TerminalEmulator} into a {@link Canvas}. * Renderer of a {@link TerminalEmulator} into a {@link Canvas}.
* * <p/>
* Saves font metrics, so needs to be recreated each time the typeface or font size changes. * Saves font metrics, so needs to be recreated each time the typeface or font size changes.
*/ */
final class TerminalRenderer { final class TerminalRenderer {
@@ -64,7 +64,8 @@ final class TerminalRenderer {
final TerminalBuffer screen = mEmulator.getScreen(); final TerminalBuffer screen = mEmulator.getScreen();
final int[] palette = mEmulator.mColors.mCurrentColors; final int[] palette = mEmulator.mColors.mCurrentColors;
if (reverseVideo) canvas.drawColor(palette[TextStyle.COLOR_INDEX_FOREGROUND], PorterDuff.Mode.SRC); if (reverseVideo)
canvas.drawColor(palette[TextStyle.COLOR_INDEX_FOREGROUND], PorterDuff.Mode.SRC);
float heightOffset = mFontLineSpacingAndAscent; float heightOffset = mFontLineSpacingAndAscent;
for (int row = topRow; row < endRow; row++) { for (int row = topRow; row < endRow; row++) {
@@ -89,7 +90,7 @@ final class TerminalRenderer {
int currentCharIndex = 0; int currentCharIndex = 0;
float measuredWidthForRun = 0.f; float measuredWidthForRun = 0.f;
for (int column = 0; column < columns;) { for (int column = 0; column < columns; ) {
final char charAtIndex = line[currentCharIndex]; final char charAtIndex = line[currentCharIndex];
final boolean charIsHighsurrogate = Character.isHighSurrogate(charAtIndex); final boolean charIsHighsurrogate = Character.isHighSurrogate(charAtIndex);
final int charsForCodePoint = charIsHighsurrogate ? 2 : 1; final int charsForCodePoint = charIsHighsurrogate ? 2 : 1;
@@ -140,28 +141,17 @@ final class TerminalRenderer {
} }
/** /**
* @param canvas * @param canvas the canvas to render on
* the canvas to render on * @param palette the color palette to look up colors from textStyle
* @param palette * @param y height offset into the canvas where to render the line: line * {@link #mFontLineSpacing}
* the color palette to look up colors from textStyle * @param startColumn the run offset in columns
* @param y * @param runWidthColumns the run width in columns - this is computed from wcwidth() and may not be what the font measures to
* height offset into the canvas where to render the line: line * {@link #mFontLineSpacing} * @param text the java char array to render text from
* @param startColumn * @param startCharIndex index into the text array where to start
* the run offset in columns * @param runWidthChars number of java characters from the text array to render
* @param runWidthColumns * @param cursor true if rendering a cursor or selection
* the run width in columns - this is computed from wcwidth() and may not be what the font measures to * @param textStyle the background, foreground and effect encoded using {@link TextStyle}
* @param text * @param reverseVideo if the screen is rendered with the global reverse video flag set
* the java char array to render text from
* @param startCharIndex
* index into the text array where to start
* @param runWidthChars
* number of java characters from the text array to render
* @param cursor
* true if rendering a cursor or selection
* @param textStyle
* the background, foreground and effect encoded using {@link TextStyle}
* @param reverseVideo
* if the screen is rendered with the global reverse video flag set
*/ */
private void drawTextRun(Canvas canvas, char[] text, int[] palette, float y, int startColumn, int runWidthColumns, int startCharIndex, int runWidthChars, private void drawTextRun(Canvas canvas, char[] text, int[] palette, float y, int startColumn, int runWidthColumns, int startCharIndex, int runWidthChars,
float mes, boolean cursor, int textStyle, boolean reverseVideo) { float mes, boolean cursor, int textStyle, boolean reverseVideo) {

View File

@@ -96,7 +96,10 @@ public final class TerminalView extends View {
@Override @Override
public boolean onSingleTapUp(MotionEvent e) { public boolean onSingleTapUp(MotionEvent e) {
if (mEmulator == null) return true; if (mEmulator == null) return true;
if (mIsSelectingText) { toggleSelectingText(null); return true; } if (mIsSelectingText) {
toggleSelectingText(null);
return true;
}
requestFocus(); requestFocus();
if (!mEmulator.isMouseTrackingActive()) { if (!mEmulator.isMouseTrackingActive()) {
if (!e.isFromSource(InputDevice.SOURCE_MOUSE)) { if (!e.isFromSource(InputDevice.SOURCE_MOUSE)) {
@@ -192,8 +195,7 @@ public final class TerminalView extends View {
} }
/** /**
* @param onKeyListener * @param onKeyListener Listener for all kinds of key events, both hardware and IME (which makes it different from that
* Listener for all kinds of key events, both hardware and IME (which makes it different from that
* available with {@link View#setOnKeyListener(OnKeyListener)}. * available with {@link View#setOnKeyListener(OnKeyListener)}.
*/ */
public void setOnKeyListener(TerminalKeyListener onKeyListener) { public void setOnKeyListener(TerminalKeyListener onKeyListener) {
@@ -203,8 +205,7 @@ public final class TerminalView extends View {
/** /**
* Attach a {@link TerminalSession} to this view. * Attach a {@link TerminalSession} to this view.
* *
* @param session * @param session The {@link TerminalSession} this view will be displaying.
* The {@link TerminalSession} this view will be displaying.
*/ */
public boolean attachSession(TerminalSession session) { public boolean attachSession(TerminalSession session) {
if (session == mTermSession) return false; if (session == mTermSession) return false;
@@ -258,7 +259,8 @@ public final class TerminalView extends View {
@Override @Override
public boolean commitText(CharSequence text, int newCursorPosition) { public boolean commitText(CharSequence text, int newCursorPosition) {
if (LOG_KEY_EVENTS) Log.i(EmulatorDebug.LOG_TAG, "IME: commitText(\"" + text + "\", " + newCursorPosition + ")"); if (LOG_KEY_EVENTS)
Log.i(EmulatorDebug.LOG_TAG, "IME: commitText(\"" + text + "\", " + newCursorPosition + ")");
if (mEmulator == null) return true; if (mEmulator == null) return true;
final int textLengthInChars = text.length(); final int textLengthInChars = text.length();
for (int i = 0; i < textLengthInChars; i++) { for (int i = 0; i < textLengthInChars; i++) {
@@ -280,11 +282,21 @@ public final class TerminalView extends View {
// E.g. penti keyboard for ctrl input. // E.g. penti keyboard for ctrl input.
ctrlHeld = true; ctrlHeld = true;
switch (codePoint) { switch (codePoint) {
case 31: codePoint = '_'; break; case 31:
case 30: codePoint = '^'; break; codePoint = '_';
case 29: codePoint = ']'; break; break;
case 28: codePoint = '\\'; break; case 30:
default: codePoint += 96; break; codePoint = '^';
break;
case 29:
codePoint = ']';
break;
case 28:
codePoint = '\\';
break;
default:
codePoint += 96;
break;
} }
} }
@@ -296,7 +308,8 @@ public final class TerminalView extends View {
@Override @Override
public boolean deleteSurroundingText(int leftLength, int rightLength) { public boolean deleteSurroundingText(int leftLength, int rightLength) {
if (LOG_KEY_EVENTS) Log.i(EmulatorDebug.LOG_TAG, "IME: deleteSurroundingText(" + leftLength + ", " + rightLength + ")"); if (LOG_KEY_EVENTS)
Log.i(EmulatorDebug.LOG_TAG, "IME: deleteSurroundingText(" + leftLength + ", " + rightLength + ")");
// Swype keyboard sometimes(?) sends this on backspace: // Swype keyboard sometimes(?) sends this on backspace:
if (leftLength == 0 && rightLength == 0) leftLength = 1; if (leftLength == 0 && rightLength == 0) leftLength = 1;
@@ -374,8 +387,7 @@ public final class TerminalView extends View {
/** /**
* Sets the text size, which in turn sets the number of rows and columns. * Sets the text size, which in turn sets the number of rows and columns.
* *
* @param textSize * @param textSize the new font size, in density-independent pixels.
* the new font size, in density-independent pixels.
*/ */
public void setTextSize(int textSize) { public void setTextSize(int textSize) {
mRenderer = new TerminalRenderer(textSize, mRenderer == null ? Typeface.MONOSPACE : mRenderer.mTypeface); mRenderer = new TerminalRenderer(textSize, mRenderer == null ? Typeface.MONOSPACE : mRenderer.mTypeface);
@@ -461,8 +473,8 @@ public final class TerminalView extends View {
mInitialTextSelection = false; mInitialTextSelection = false;
break; break;
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
int distanceFromSel1 = Math.abs(cx-mSelX1) + Math.abs(cy-mSelY1); int distanceFromSel1 = Math.abs(cx - mSelX1) + Math.abs(cy - mSelY1);
int distanceFromSel2 = Math.abs(cx-mSelX2) + Math.abs(cy-mSelY2); int distanceFromSel2 = Math.abs(cx - mSelX2) + Math.abs(cy - mSelY2);
mIsDraggingLeftSelection = distanceFromSel1 <= distanceFromSel2; mIsDraggingLeftSelection = distanceFromSel1 <= distanceFromSel2;
mSelectionDownX = ev.getX(); mSelectionDownX = ev.getX();
mSelectionDownY = ev.getY(); mSelectionDownY = ev.getY();
@@ -490,11 +502,14 @@ public final class TerminalView extends View {
// Switch handles. // Switch handles.
mIsDraggingLeftSelection = !mIsDraggingLeftSelection; mIsDraggingLeftSelection = !mIsDraggingLeftSelection;
int tmpX1 = mSelX1, tmpY1 = mSelY1; int tmpX1 = mSelX1, tmpY1 = mSelY1;
mSelX1 = mSelX2; mSelY1 = mSelY2; mSelX1 = mSelX2;
mSelX2 = tmpX1; mSelY2 = tmpY1; mSelY1 = mSelY2;
mSelX2 = tmpX1;
mSelY2 = tmpY1;
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) mActionMode.invalidateContentRect(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
mActionMode.invalidateContentRect();
invalidate(); invalidate();
break; break;
default: default:
@@ -533,7 +548,8 @@ public final class TerminalView extends View {
@Override @Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) { public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (LOG_KEY_EVENTS) Log.i(EmulatorDebug.LOG_TAG, "onKeyPreIme(keyCode=" + keyCode + ", event=" + event + ")"); if (LOG_KEY_EVENTS)
Log.i(EmulatorDebug.LOG_TAG, "onKeyPreIme(keyCode=" + keyCode + ", event=" + event + ")");
if (keyCode == KeyEvent.KEYCODE_BACK) { if (keyCode == KeyEvent.KEYCODE_BACK) {
if (mIsSelectingText) { if (mIsSelectingText) {
toggleSelectingText(null); toggleSelectingText(null);
@@ -553,7 +569,8 @@ public final class TerminalView extends View {
@Override @Override
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {
if (LOG_KEY_EVENTS) Log.i(EmulatorDebug.LOG_TAG, "onKeyDown(keyCode=" + keyCode + ", isSystem()=" + event.isSystem() + ", event=" + event + ")"); if (LOG_KEY_EVENTS)
Log.i(EmulatorDebug.LOG_TAG, "onKeyDown(keyCode=" + keyCode + ", isSystem()=" + event.isSystem() + ", event=" + event + ")");
if (mEmulator == null) return true; if (mEmulator == null) return true;
if (mOnKeyListener.onKeyDown(keyCode, event, mTermSession)) { if (mOnKeyListener.onKeyDown(keyCode, event, mTermSession)) {
@@ -591,7 +608,8 @@ public final class TerminalView extends View {
int effectiveMetaState = event.getMetaState() & ~bitsToClear; int effectiveMetaState = event.getMetaState() & ~bitsToClear;
int result = event.getUnicodeChar(effectiveMetaState); int result = event.getUnicodeChar(effectiveMetaState);
if (LOG_KEY_EVENTS) Log.i(EmulatorDebug.LOG_TAG, "KeyEvent#getUnicodeChar(" + effectiveMetaState + ") returned: " + result); if (LOG_KEY_EVENTS)
Log.i(EmulatorDebug.LOG_TAG, "KeyEvent#getUnicodeChar(" + effectiveMetaState + ") returned: " + result);
if (result == 0) { if (result == 0) {
return true; return true;
} }
@@ -599,7 +617,8 @@ public final class TerminalView extends View {
int oldCombiningAccent = mCombiningAccent; int oldCombiningAccent = mCombiningAccent;
if ((result & KeyCharacterMap.COMBINING_ACCENT) != 0) { if ((result & KeyCharacterMap.COMBINING_ACCENT) != 0) {
// If entered combining accent previously, write it out: // If entered combining accent previously, write it out:
if (mCombiningAccent != 0) inputCodePoint(mCombiningAccent, controlDownFromEvent, leftAltDownFromEvent); if (mCombiningAccent != 0)
inputCodePoint(mCombiningAccent, controlDownFromEvent, leftAltDownFromEvent);
mCombiningAccent = result & KeyCharacterMap.COMBINING_ACCENT_MASK; mCombiningAccent = result & KeyCharacterMap.COMBINING_ACCENT_MASK;
} else { } else {
if (mCombiningAccent != 0) { if (mCombiningAccent != 0) {
@@ -681,15 +700,14 @@ public final class TerminalView extends View {
/** /**
* Called when a key is released in the view. * Called when a key is released in the view.
* *
* @param keyCode * @param keyCode The keycode of the key which was released.
* The keycode of the key which was released. * @param event A {@link KeyEvent} describing the event.
* @param event
* A {@link KeyEvent} describing the event.
* @return Whether the event was handled. * @return Whether the event was handled.
*/ */
@Override @Override
public boolean onKeyUp(int keyCode, KeyEvent event) { public boolean onKeyUp(int keyCode, KeyEvent event) {
if (LOG_KEY_EVENTS) Log.i(EmulatorDebug.LOG_TAG, "onKeyUp(keyCode=" + keyCode + ", event=" + event + ")"); if (LOG_KEY_EVENTS)
Log.i(EmulatorDebug.LOG_TAG, "onKeyUp(keyCode=" + keyCode + ", event=" + event + ")");
if (mEmulator == null) return true; if (mEmulator == null) return true;
if (mOnKeyListener.onKeyUp(keyCode, event)) { if (mOnKeyListener.onKeyUp(keyCode, event)) {
@@ -744,12 +762,12 @@ public final class TerminalView extends View {
final int gripHandleMargin = gripHandleWidth / 4; // See the png. final int gripHandleMargin = gripHandleWidth / 4; // See the png.
int right = Math.round((mSelX1) * mRenderer.mFontWidth) + gripHandleMargin; int right = Math.round((mSelX1) * mRenderer.mFontWidth) + gripHandleMargin;
int top = (mSelY1+1 - mTopRow)*mRenderer.mFontLineSpacing + mRenderer.mFontLineSpacingAndAscent; int top = (mSelY1 + 1 - mTopRow) * mRenderer.mFontLineSpacing + mRenderer.mFontLineSpacingAndAscent;
mLeftSelectionHandle.setBounds(right - gripHandleWidth, top, right, top + mLeftSelectionHandle.getIntrinsicHeight()); mLeftSelectionHandle.setBounds(right - gripHandleWidth, top, right, top + mLeftSelectionHandle.getIntrinsicHeight());
mLeftSelectionHandle.draw(canvas); mLeftSelectionHandle.draw(canvas);
int left = Math.round((mSelX2+1)*mRenderer.mFontWidth) - gripHandleMargin; int left = Math.round((mSelX2 + 1) * mRenderer.mFontWidth) - gripHandleMargin;
top = (mSelY2+1 - mTopRow) *mRenderer.mFontLineSpacing + mRenderer.mFontLineSpacingAndAscent; top = (mSelY2 + 1 - mTopRow) * mRenderer.mFontLineSpacing + mRenderer.mFontLineSpacingAndAscent;
mRightSelectionHandle.setBounds(left, top, left + gripHandleWidth, top + mRightSelectionHandle.getIntrinsicHeight()); mRightSelectionHandle.setBounds(left, top, left + gripHandleWidth, top + mRightSelectionHandle.getIntrinsicHeight());
mRightSelectionHandle.draw(canvas); mRightSelectionHandle.draw(canvas);
} }
@@ -780,10 +798,10 @@ public final class TerminalView extends View {
TerminalBuffer screen = mEmulator.getScreen(); TerminalBuffer screen = mEmulator.getScreen();
if (!" ".equals(screen.getSelectedText(mSelX1, mSelY1, mSelX1, mSelY1))) { if (!" ".equals(screen.getSelectedText(mSelX1, mSelY1, mSelX1, mSelY1))) {
// Selecting something other than whitespace. Expand to word. // Selecting something other than whitespace. Expand to word.
while (mSelX1 > 0 && !"".equals(screen.getSelectedText(mSelX1-1, mSelY1, mSelX1-1, mSelY1))) { while (mSelX1 > 0 && !"".equals(screen.getSelectedText(mSelX1 - 1, mSelY1, mSelX1 - 1, mSelY1))) {
mSelX1--; mSelX1--;
} }
while (mSelX2 < mEmulator.mColumns-1 && !"".equals(screen.getSelectedText(mSelX2+1, mSelY1, mSelX2+1, mSelY1))) { while (mSelX2 < mEmulator.mColumns - 1 && !"".equals(screen.getSelectedText(mSelX2 + 1, mSelY1, mSelX2 + 1, mSelY1))) {
mSelX2++; mSelX2++;
} }
} }
@@ -796,7 +814,7 @@ public final class TerminalView extends View {
final ActionMode.Callback callback = new ActionMode.Callback() { final ActionMode.Callback callback = new ActionMode.Callback() {
@Override @Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) { public boolean onCreateActionMode(ActionMode mode, Menu menu) {
final int[] ACTION_MODE_ATTRS = { android.R.attr.actionModeCopyDrawable, android.R.attr.actionModePasteDrawable, }; final int[] ACTION_MODE_ATTRS = {android.R.attr.actionModeCopyDrawable, android.R.attr.actionModePasteDrawable,};
TypedArray styledAttributes = getContext().obtainStyledAttributes(ACTION_MODE_ATTRS); TypedArray styledAttributes = getContext().obtainStyledAttributes(ACTION_MODE_ATTRS);
try { try {
int show = MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT; int show = MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT;