Skip to content
This repository was archived by the owner on Nov 11, 2018. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ if (NOT MINIMAL_FLAGS)
endif (NOT MINIMAL_FLAGS)

configure_file(${CMAKE_SOURCE_DIR}/data/Startup/bash_startup.in ${CMAKE_BINARY_DIR}/Startup/bash_startup @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/data/Startup/zsh_startup.in ${CMAKE_BINARY_DIR}/Startup/zsh_startup @ONLY)

set(PKGS clutter-gtk-1.0 mx-1.0 keybinder-3.0 gee-0.8)

Expand Down Expand Up @@ -104,6 +105,9 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/ColorSchemes DESTINATION shar
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/KeyBindings DESTINATION share/finalterm)
install(DIRECTORY ${CMAKE_BINARY_DIR}/Startup DESTINATION share/finalterm)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/Startup/preexec.bash DESTINATION share/finalterm/Startup)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/Startup/zsh_functions DESTINATION share/finalterm/Startup)
file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/zsh_functions/*")
install(FILES ${files} DESTINATION share/finalterm/Stertup/zsh_functions)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/TerminalCommands DESTINATION share/finalterm)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/Termlets DESTINATION share/finalterm FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/TextMenus DESTINATION share/finalterm)
Expand Down
8 changes: 8 additions & 0 deletions README-ZSH.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Requirements
- gsettings set org.gnome.finalterm shell-path /usr/bin/zsh
- add the following to ~/.zshrc:
```
if [ -n "$FINALTERMSCRIPT" ]; then
. $FINALTERMSCRIPT
fi
```
11 changes: 11 additions & 0 deletions data/Startup/zsh_functions/final_term_control_sequence
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# NOTE: xterm properly ignores sequences of this type as unknown,
# while some other terminals (such as GNOME Terminal) print them
control_sequence="\e]133;"
for argument in "$@"; do
control_sequence="$control_sequence$argument;"
done
# TODO: Remove last semicolon
control_sequence="$control_sequence\a"

# TODO: Should "-ne" be added here?
echo "$control_sequence"
1 change: 1 addition & 0 deletions data/Startup/zsh_functions/send_control_sequence
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
echo -ne "$1"
1 change: 1 addition & 0 deletions data/Startup/zsh_functions/send_progress
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
send_control_sequence "$(final_term_control_sequence 'G' "$1" "$2")"
1 change: 1 addition & 0 deletions data/Startup/zsh_functions/text_menu_end
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
echo "$(final_term_control_sequence 'F' "$1")"
3 changes: 3 additions & 0 deletions data/Startup/zsh_functions/text_menu_start
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# NOTE: Nested double quotes look strange, but are both valid and necessary;
# see http://stackoverflow.com/questions/4031007
echo "$(final_term_control_sequence 'E' "$1")"
83 changes: 83 additions & 0 deletions data/Startup/zsh_startup.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/zsh

# Final Term's customizations start here
finalterm_fpath="@PKGDATADIR@/Startup/zsh_functions"
if [ -d $finalterm_fpath ]; then
fpath=($finalterm_fpath $fpath)
fi
FPATH="${finalterm_fpath}:${FPATH}"
export FPATH

autoload send_control_sequence
autoload final_term_control_sequence

# Logic for prompt and command detection
function send_return_code() {
# Send sequence containing the return code of the last command
send_control_sequence "$(final_term_control_sequence 'D' "$?")"
}

precmd() {
# Send sequence marking a command prompt
send_control_sequence "$(final_term_control_sequence 'A')"
}

preexec() {
# Send sequence containing the command to be executed
send_control_sequence "$(final_term_control_sequence 'C' "$1")"
}

PROMPT_COMMAND=send_return_code;$PROMPT_COMMAND

# Send sequence marking the start of a command
PS1=$PS1$(final_term_control_sequence 'B')


# Logic for terminal commands
function trim() {
local var=$1
var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters
var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters
echo -n "$var"
}

function send_commands() {
send_control_sequence "$(final_term_control_sequence 'H' "$1" '#' "${@:2}")"
}

pushd "@PKGDATADIR@/TerminalCommands" > /dev/null
while IFS= read -r line; do
stripped_line=$(trim "$line")

if [ -n "$stripped_line" ]; then
# Non-empty line
if [ "${stripped_line:0:1}" != "#" ]; then
# Non-comment line
# Split on "=" character and escape double quotes used for command arguments
name=$(trim "${stripped_line%%\=*}")
cmds=$(trim "${${stripped_line#*\=}//\"/\\\"}")

alias ",$name"="send_commands \"$cmds\""
fi
fi
done <*.ftcommands
popd > /dev/null


# Termlet-related logic
function run_termlet() {
if [ -t 1 ]; then
/usr/bin/zsh "@PKGDATADIR@/Termlets/$@"
else
/usr/bin/zsh "$@"
fi
}

# Set up termlet aliases
pushd "@PKGDATADIR@/Termlets" > /dev/null
for filename in *; do
alias $filename="run_termlet '$filename'"
done
popd > /dev/null

cd ~
7 changes: 7 additions & 0 deletions data/Termlets/ls
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
#!/bin/bash

if [ -n "$ZSH_VERSION" ]; then
autoload text_menu_start
autoload text_menu_end
autoload final_term_control_sequence
autoload send_control_sequence
fi

ls_output=$(ls "$@")
dir_begin_mark=$(text_menu_start '2')
dir_end_mark=$(text_menu_end '2')
Expand Down
28 changes: 23 additions & 5 deletions data/Termlets/ps
Original file line number Diff line number Diff line change
@@ -1,26 +1,44 @@
#!/bin/bash

if [ -n "$ZSH_VERSION" ]; then
autoload text_menu_start
autoload text_menu_end
autoload final_term_control_sequence
autoload send_control_sequence
fi

# IFS is '\n'
IFS=$'\012'
psoutput=($(ps "$@"))

headeridx=0
while [ -z ${psoutput[$headeridx]+x} ]; do
((headeridx+=1))
done

# Just in case PPID could be displayed before PID, search for ' PID'
pid_index=$(awk -v a="${psoutput[0]}" -v b=' PID' 'BEGIN{print index(a,b)}')
pid_index=$(awk -v a="${psoutput[$headeridx]}" -v b=' PID' 'BEGIN{print index(a,b)}')
# don’t use $() in loops, as it spawns a sub-process, so get markings out of the loop.
begin_mark=$(text_menu_start '3')
end_mark=$(text_menu_end '3')
# last character position of PID display.
let pid_end=pid_index+4
# display 1st line as is, then destroy it.
echo -e ${psoutput[0]}
unset psoutput[0]

# display header line as is and destroy it
echo -e ${psoutput[$headeridx]}
if [ -n "$ZSH_VERSION" ]; then
psoutput[$headeridx]=()
else
unset psoutput[$headeridx]
fi

for line in ${psoutput[@]}; do
# Content line
left_part=${line:0:${pid_end}-1}
pid_part=${left_part##* }
# Remove pid_part from left_part
left_part=${left_part:0:${#left_part}-${#pid_part}}
right_part=${line:pid_end-1}
right_part=${line:${pid_end}-1}
modified_line="$left_part$begin_mark$pid_part$end_mark$right_part"
echo -e "$modified_line"
done
7 changes: 7 additions & 0 deletions data/Termlets/wget
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
#!/bin/bash

if [ -n "$ZSH_VERSION" ]; then
autoload send_progress
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that autoload is not enabled by default in bash.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, that is why the test for $ZSH_VERSION, though thinking about it a bit, it might make sense to create zsh wrappers that do the autoloading and then source the bash scripts instead.

autoload send_control_sequence
autoload final_term_control_sequence
setopt BASH_REMATCH
fi

# TODO: Multiple file downloads?

# Note that wget writes its output to STDERR instead of STDOUT
Expand Down
2 changes: 1 addition & 1 deletion data/org.gnome.finalterm.gschema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
</key>
<key type="s" name="shell-path">
<default>'/bin/bash'</default>
<summary>Path to the shell executable which is to be run (NOTE: Only bash is currently supported)</summary>
<summary>Path to the shell executable which is to be run (NOTE: Only bash and zsh are currently supported)</summary>
<description></description>
</key>
<key type="as" name="shell-arguments">
Expand Down
27 changes: 24 additions & 3 deletions src/Terminal.vala
Original file line number Diff line number Diff line change
Expand Up @@ -242,16 +242,37 @@ public class Terminal : Object {
private void run_shell() {
Environment.set_variable("TERM", Settings.get_default().emulated_terminal, true);

string[] arguments = { Settings.get_default().shell_path, "--rcfile",
Config.PKGDATADIR + "/Startup/bash_startup", "-i" };
string shell = Environment.get_variable("SHELL") ?? Settings.get_default().shell_path;
string shell_basename = Filename.display_basename(shell);

string[] valid_shells = { "zsh", "bash" };

if (!(shell_basename in valid_shells)){
message(_("shell defined in environment is not supported, falling back to bash"));
shell = Settings.get_default().shell_path;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Settings.get_default().shell_path returns an invalid shell, we will proceed with that invalid shell from this point anyway. Instead, this should somehow "hardcode" bash so we have a true fallback.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, I'll add logic to force bash if Settings.get_default().shell_path is not a valid shell. Thinking about it, I should also test to make sure that the shell referenced by $SHELL or shell_path actually exists as well.

shell_basename = Filename.display_basename(shell);
}

string shell_include = Config.PKGDATADIR + "/Startup/" + shell_basename + "_startup";

string[] arguments = {};
switch(shell_basename){
case "bash":
arguments = { shell, "--rcfile", shell_include, "-i" };
break;
case "zsh":
Environment.set_variable("FINALTERMSCRIPT", shell_include, true);
arguments = { shell, "-i" };
break;
}

// Add custom shell arguments
foreach (var argument in Settings.get_default().shell_arguments) {
arguments += argument;
}

// Replace child process with shell process
Posix.execvp(Settings.get_default().shell_path, arguments);
Posix.execvp(shell, arguments);

// If this line is reached, execvp() must have failed
critical(_("execvp failed"));
Expand Down