Skip to content
This repository has been archived by the owner on Nov 11, 2018. It is now read-only.

[DO NOT MERGE} initial zsh support #355

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
21 changes: 19 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,24 @@ if (NOT MINIMAL_FLAGS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb")
endif (NOT MINIMAL_FLAGS)

find_program(BASHEXE bash /bin /usr/bin /usr/local/bin)
if(NOT DEFINED BASHEXE)
set(BASHEXE "/bin/bash")
endif(NOT DEFINED BASHEXE)
configure_file(${CMAKE_SOURCE_DIR}/data/Startup/bash_startup.in ${CMAKE_BINARY_DIR}/Startup/bash_startup @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/data/Startup/preexec.bash.in ${CMAKE_BINARY_DIR}/Startup/preexec.bash @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/data/Termlets/bash/ps.in ${CMAKE_BINARY_DIR}/Termlets/bash/ps @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/data/Termlets/bash/ls.in ${CMAKE_BINARY_DIR}/Termlets/bash/ls @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/data/Termlets/bash/wget.in ${CMAKE_BINARY_DIR}/Termlets/bash/wget @ONLY)

find_program(ZSHEXE zsh /bin /usr/bin /usr/local/bin)
if(NOT DEFINED ZSHEXE)
set(ZSHEXE "/usr/bin/zsh")
endif(NOT DEFINED ZSHEXE)
configure_file(${CMAKE_SOURCE_DIR}/data/Startup/zsh_startup.in ${CMAKE_BINARY_DIR}/Startup/zsh_startup @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/data/Termlets/zsh/ps.in ${CMAKE_BINARY_DIR}/Termlets/zsh/ps @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/data/Termlets/zsh/ls.in ${CMAKE_BINARY_DIR}/Termlets/zsh/ls @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/data/Termlets/zsh/wget.in ${CMAKE_BINARY_DIR}/Termlets/zsh/wget @ONLY)

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

Expand Down Expand Up @@ -103,9 +120,9 @@ install(TARGETS finalterm RUNTIME DESTINATION bin)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/ColorSchemes DESTINATION share/finalterm)
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)
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_BINARY_DIR}/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)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/Themes DESTINATION share/finalterm)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/Icons/hicolor DESTINATION share/icons)
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
- $SHELL set to zsh
- add the following to ~/.zshrc:
```
if [ -n "$FINALTERMSCRIPT" ]; then
. $FINALTERMSCRIPT
fi
```
6 changes: 3 additions & 3 deletions data/Startup/bash_startup.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!@BASHEXE@

# Include default startup file so that user's settings are respected
[[ -r ~/.bashrc ]] && source ~/.bashrc
Expand Down Expand Up @@ -112,14 +112,14 @@ export -f send_progress

function run_termlet() {
if [ -t 1 ]; then
"@PKGDATADIR@/Termlets/$@"
"@PKGDATADIR@/Termlets/bash/$@"
else
"$@"
fi
}

# Set up termlet aliases
pushd "@PKGDATADIR@/Termlets" > /dev/null
pushd "@PKGDATADIR@/Termlets/bash" > /dev/null
for filename in *; do
alias $filename="run_termlet '$filename'"
done
Expand Down
2 changes: 1 addition & 1 deletion data/Startup/preexec.bash → data/Startup/preexec.bash.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!@BASHEXE@

# NOTE: This file is taken (with minor modifications) from
# Glyph Lefkowitz's blog post "This bash shell is now fully operational!"
Expand Down
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"
2 changes: 2 additions & 0 deletions data/Startup/zsh_functions/send_control_sequence
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
setopt no_prompt_cr
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")"
82 changes: 82 additions & 0 deletions data/Startup/zsh_startup.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!@ZSHEXE@

# 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
send_return_code() {
# Send sequence containing the return code of the last command
send_control_sequence "$(final_term_control_sequence 'D' "$?")"
}

precmd_hook() {
# Send sequence marking a command prompt
send_control_sequence "$(final_term_control_sequence 'A')"
}
precmd_functions=( send_return_code $preexec_functions precmd_hook )

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

PROMPT="${PROMPT}$(final_term_control_sequence 'B')"

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

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
"@PKGDATADIR@/Termlets/zsh/$@"
else
"$@"
fi
}

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

cd ~
2 changes: 1 addition & 1 deletion data/Termlets/ls → data/Termlets/bash/ls.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!@BASHEXE@

ls_output=$(ls "$@")
dir_begin_mark=$(text_menu_start '2')
Expand Down
19 changes: 13 additions & 6 deletions data/Termlets/ps → data/Termlets/bash/ps.in
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
#!/bin/bash
#!@BASHEXE@

# 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]}
unset psoutput[$headeridx]

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
2 changes: 1 addition & 1 deletion data/Termlets/wget → data/Termlets/bash/wget.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!@BASHEXE@

# TODO: Multiple file downloads?

Expand Down
38 changes: 38 additions & 0 deletions data/Termlets/zsh/ls.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!@ZSHEXE@

autoload text_menu_start
autoload text_menu_end
autoload final_term_control_sequence
autoload send_control_sequence

ls_output=$(ls "$@")
dir_begin_mark=$(text_menu_start '2')
dir_end_mark=$(text_menu_end '2')
file_begin_mark=$(text_menu_start '1')
file_end_mark=$(text_menu_end '1')

# Surround with additional newlines to facilitate matching (see below)
ls_output=$'\n'$ls_output$'\n'

# TODO: Search for files in directory passed to ls rather than the current directory
for filename in *; do
if [[ -d $filename ]]; then
file_substitution="$dir_begin_mark$filename$dir_end_mark"
else
file_substitution="$file_begin_mark$filename$file_end_mark"
fi

# Short format ("ls"; each filename on a single line)
ls_output=${ls_output/$'\n'$filename$'\n'/$'\n'$file_substitution$'\n'}
# Long format ("ls -l")
ls_output=${ls_output/ $filename$'\n'/ $file_substitution$'\n'}
# Long format; symlinks
ls_output=${ls_output/ $filename ->/ $file_substitution ->}
done

# Strip leading newline
ls_output=${ls_output#$'\n'}
# Strip trailing newline
ls_output=${ls_output%$'\n'}

echo -e "$ls_output"
38 changes: 38 additions & 0 deletions data/Termlets/zsh/ps.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!@ZSHEXE@

autoload text_menu_start
autoload text_menu_end
autoload final_term_control_sequence
autoload send_control_sequence

# 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[$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 header line as is and destroy it
echo -e ${psoutput[$headeridx]}
psoutput[$headeridx]=()

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}
modified_line="$left_part$begin_mark$pid_part$end_mark$right_part"
echo -e "$modified_line"
done
35 changes: 35 additions & 0 deletions data/Termlets/zsh/wget.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!@ZSHEXE@

autoload send_progress
autoload send_control_sequence
autoload final_term_control_sequence
setopt BASH_REMATCH

# TODO: Multiple file downloads?

# Note that wget writes its output to STDERR instead of STDOUT
wget --progress=bar:force "$@" 2>&1 |

while IFS= read -r line; do
echo "$line"

if [[ $line == "" ]]; then
# Progress bar reached
# => Switch to CR as line separator to receive
# individual progress bar updates
while IFS= read -r -d $'\r' line; do
# Extract current progress percentage
if [[ $line =~ ^\ ?([0-9]{1,3})% ]]; then
send_progress "${BASH_REMATCH[1]}" "Downloading $1..."
fi

echo -ne "\r$line"
done

# Process completed
send_progress "-1" ""

# Print remaining output
echo -ne "\r$line"
fi
done
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
25 changes: 15 additions & 10 deletions src/Command.vala
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,22 @@ public class Command : Object {
foreach (var parameter in parameters) {
var substitute_parameter = parameter;

// Replace placeholder "%i" with placeholder_substitutes[i - 1]
for (int i = 0; i < placeholder_substitutes.size; i++) {
substitute_parameter = substitute_parameter.replace(
"%" + (i + 1).to_string(),
placeholder_substitutes.get(i));
try {
// Replace placeholder "%i" with placeholder_substitutes[i - 1]
for (int i = 0; i < placeholder_substitutes.size; i++) {
substitute_parameter = substitute_parameter.replace(
"%" + (i + 1).to_string(),
placeholder_substitutes.get(i));
message(_("placeholder_substitute: %s"), placeholder_substitutes.get(i));
}

// Remove remaining placeholders
substitute_parameter = placeholder_pattern.replace(substitute_parameter,
-1, 0, "");
substitute_command.parameters.add(substitute_parameter);
} catch (GLib.RegexError e) {
error(_("Error substituting parameter. placeholder_pattern: %s substitute_parameter: %s, exception: %s"), placeholder_pattern.get_pattern, substitute_parameter, e.message);
}

// Remove remaining placeholders
substitute_parameter = placeholder_pattern.replace(substitute_parameter, -1, 0, "");

substitute_command.parameters.add(substitute_parameter);
}

substitute_command.execute();
Expand Down
Loading