|
#!/usr/bin/env bash |
|
|
|
# Name of my laptop to check if we're local editing |
|
master_hostname="kaypro" |
|
local_editor_cmd="atom" |
|
|
|
# |
|
# Petonic version {2016-11-20 SUN 12:54} |
|
# Modified for ///READONLY/// auto -f {2016-11-26 SAT 10:01} |
|
# Modified for USE_NFS mountpoint [2017-04-16 SUN 12:57] |
|
# |
|
# rmate |
|
# Copyright (C) 2011-2015 by Harald Lapp <[email protected]> |
|
# |
|
# This program is free software: you can redistribute it and/or modify |
|
# it under the terms of the GNU General Public License as published by |
|
# the Free Software Foundation, either version 3 of the License, or |
|
# (at your option) any later version. |
|
# |
|
# This program is distributed in the hope that it will be useful, |
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
# GNU General Public License for more details. |
|
# |
|
# You should have received a copy of the GNU General Public License |
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
# |
|
# This script can be found at: |
|
# https://github.com/aurora/rmate |
|
# |
|
|
|
# |
|
# This script is a pure bash compatible shell script implementing remote |
|
# textmate functionality |
|
# |
|
|
|
# |
|
# Thanks very much to all users and contributors! All bug-reports, |
|
# feature-requests, patches, etc. are greatly appreciated! :-) |
|
# |
|
|
|
# init |
|
# |
|
version="0.9.6" |
|
version_date="2015-09-15" |
|
version_string="rmate-sh $version ($version_date)" |
|
|
|
# determine hostname |
|
function hostname_command(){ |
|
if command -v hostname >/dev/null 2>&1; then |
|
echo "hostname" |
|
else { |
|
HOSTNAME_DESCRIPTOR="/proc/sys/kernel/hostname" |
|
if test -r "$HOSTNAME_DESCRIPTOR"; then |
|
echo "cat $HOSTNAME_DESCRIPTOR" |
|
else |
|
echo "hostname" |
|
fi |
|
} |
|
fi |
|
} |
|
|
|
hostname=$($(hostname_command)) |
|
|
|
readonly="" |
|
[ -n "$SUDO_UID" ] && sudo_string=" ### " |
|
|
|
|
|
# default configuration |
|
host=localhost |
|
port=52698 |
|
|
|
function load_config { |
|
local rc_file=$1 |
|
local row |
|
|
|
local host_pattern="^host(:[[:space:]]+|=)([^ ]+)" |
|
local port_pattern="^port(:[[:space:]]+|=)([0-9]+)" |
|
|
|
readonly="" |
|
|
|
|
|
if [ -f "$rc_file" ]; then |
|
while read row; do |
|
if [[ "$row" =~ $host_pattern ]]; then |
|
host=${BASH_REMATCH[2]} |
|
elif [[ "$row" =~ $port_pattern ]]; then |
|
port=${BASH_REMATCH[2]} |
|
fi |
|
done < "$rc_file" |
|
fi |
|
} |
|
|
|
for i in "/etc/${0##*/}" ~/."${0##*/}/${0##*/}.rc" ~/."${0##*/}.rc"; do |
|
load_config $i |
|
done |
|
|
|
host="${RMATE_HOST:-$host}" |
|
port="${RMATE_PORT:-$port}" |
|
|
|
logger "=--------------- Rmate: start of args" |
|
for i in "$@"; do |
|
logger "rmate arg is <$i>" |
|
done |
|
|
|
# misc initialization |
|
filepaths=() |
|
displaynames=() |
|
selections=() |
|
filetypes=() |
|
verbose=false |
|
nowait=true |
|
force=false |
|
check_only=false |
|
use_nfs=true |
|
|
|
# process command-line parameters |
|
# |
|
function showusage { |
|
echo "usage: $(basename $0) [arguments] file-path edit specified file |
|
or: $(basename $0) [arguments] - read text from stdin |
|
|
|
-H, --host HOST Connect to HOST. Use 'auto' to detect the host from |
|
SSH. Defaults to $host. |
|
-p, --port PORT Port number to use for connection. Defaults to $port. |
|
-w, --[no-]wait Wait for file to be closed by TextMate. |
|
-l, --line LINE Place caret on line number after loading file. |
|
-m, --name NAME The display name shown in TextMate. |
|
-t, --type TYPE Treat file as having specified type. |
|
-n, --new Open in a new window (Sublime Text). |
|
-r, --remote Do not use .atom-nfs config files |
|
-v, --verbose Verbose logging messages. |
|
-h, --help Display this usage information. |
|
-f, --force Force previous App to activate when editing is done |
|
-c, --check Returns immediately. Status set whether RATOM is running. |
|
--version Show version and exit. |
|
" |
|
} |
|
|
|
function log { |
|
if [[ $verbose = true ]]; then |
|
echo "$@" 1>&2 |
|
fi |
|
logger "$@" |
|
} |
|
|
|
function dirpath { |
|
(cd `dirname "$1"` >/dev/null 2>/dev/null; pwd -P) |
|
} |
|
|
|
function canonicalize { |
|
filepath="$1" |
|
dir=`dirpath "$filepath"` |
|
if [ -L "$filepath" ]; then |
|
relativepath=`cd "$dir"; readlink \`basename "$filepath"\`` |
|
result=`dirpath "$relativepath"`/`basename "$relativepath"` |
|
else |
|
result=`basename "$filepath"` |
|
if [ "$dir" = '/' ]; then |
|
result="$dir$result" |
|
else |
|
result="$dir/$result" |
|
fi |
|
fi |
|
echo $result |
|
} |
|
|
|
while test "${1:0:1}" = "-"; do |
|
case $1 in |
|
-) |
|
break |
|
;; |
|
-H|--host) |
|
host=$2 |
|
shift |
|
;; |
|
-p|--port) |
|
port=$2 |
|
shift |
|
;; |
|
-w|--wait) |
|
nowait=false |
|
;; |
|
--no-wait) |
|
nowait=true |
|
;; |
|
-l|--line) |
|
selections+=($2) |
|
shift |
|
;; |
|
-r|--remote) |
|
use_nfs=false |
|
shift |
|
;; |
|
-m|--name) |
|
displaynames+=("$2") |
|
shift |
|
;; |
|
-t|--type) |
|
filetypes+=($2) |
|
shift |
|
;; |
|
-n|--new) |
|
new=true |
|
;; |
|
-f|--force) |
|
force=true |
|
;; |
|
-c|--check) |
|
check_only=true |
|
;; |
|
-v|--verbose) |
|
verbose=true |
|
;; |
|
--version) |
|
echo $version_string |
|
exit 1 |
|
;; |
|
-h|-\?|--help) |
|
showusage |
|
exit 1 |
|
;; |
|
*) |
|
showusage |
|
exit 1 |
|
;; |
|
esac |
|
|
|
shift |
|
done |
|
|
|
if [[ "$host" = "auto" && "$SSH_CONNECTION" != "" ]]; then |
|
host=${SSH_CONNECTION%% *} |
|
fi |
|
|
|
filepaths=("$@") |
|
|
|
if [ "$filepaths" = "" ]; then |
|
if [[ $nowait = false ]]; then |
|
filepaths='-' |
|
else |
|
case "$-" in |
|
*i*) |
|
showusage |
|
exit 1 |
|
;; |
|
*) |
|
filepaths='-' |
|
;; |
|
esac |
|
fi |
|
fi |
|
|
|
|
|
#------------------------------------------------------------ |
|
# main |
|
#------------------------------------------------------------ |
|
|
|
function open_file { |
|
|
|
index="$1" |
|
filepath="${filepaths[$index]}" |
|
selection="${selections[$index]}" |
|
filetype="${filetypes[$index]}" |
|
displayname="${displaynames[$index]}" |
|
|
|
|
|
|
|
|
|
if [ "$filepath" != "-" ]; then |
|
realpath=`canonicalize "$filepath"` |
|
log $realpath |
|
|
|
# Check to see if we're on my laptop |
|
if [[ $hostname = $master_hostname ]]; then |
|
$local_editor_cmd "$filepath" |
|
else |
|
if [ -d "$filepath" -a ! ${use_nfs} ]; then |
|
log "$filepath is a directory and rmate is unable to handle directories." |
|
exit 1 |
|
fi |
|
|
|
if [ -f "$realpath" -a ! -w "$realpath" ]; then |
|
readonly="///READONLY/// - " |
|
if [[ $verbose = true ]]; then |
|
log "File $filepath is not writable! Opening anyway." |
|
fi |
|
fi |
|
|
|
if [ "$displayname" = "" ]; then |
|
displayname="$hostname:$filepath" |
|
fi |
|
fi |
|
else |
|
displayname="$hostname:untitled" |
|
fi |
|
|
|
displayname="${readonly}_SSH_${displayname}" |
|
[ "$sudo_string" ] && displayname="${sudo_string} ${displayname} ${sudo_string}" |
|
|
|
nfs_pathname="" |
|
if ${use_nfs} ; then |
|
nfs_map="`rnfs ${realpath} 2>/dev/null`" && nfs_pathname="${nfs_map}" |
|
fi |
|
|
|
# echo "use_nfs = <$use_nfs>" |
|
# echo "nfs_map = <$nfsmap>" |
|
# echo "nfs_pathname = <$nfs_pathname>" |
|
|
|
echo "open" 1>&3 |
|
echo "display-name: ///NFS/// $displayname" 1>&3 |
|
echo "real-path: NFS_$realpath" 1>&3 |
|
echo "data-on-save: yes" 1>&3 |
|
echo "re-activate: yes" 1>&3 |
|
if [ -n "${nfs_pathname}" ]; then |
|
echo "nfs-open: ${nfs_pathname}" 1>&3 |
|
echo "Using NFS-OPEN with <${nfs_pathname}>" |
|
# exit 9 |
|
fi |
|
echo "token: $filepath" 1>&3 |
|
|
|
if [[ $new = true ]]; then |
|
echo "new: yes" 1>&3 |
|
fi |
|
|
|
if [ "$selection" != "" ]; then |
|
echo "selection: $selection" 1>&3 |
|
fi |
|
|
|
if [ "$filetype" != "" ]; then |
|
echo "file-type: $filetype" 1>&3 |
|
fi |
|
|
|
if [ "$filepath" != "-" ] && [ -f "$filepath" ]; then |
|
filesize=`ls -lLn "$realpath" | awk '{print $5}'` |
|
echo "data: $filesize" 1>&3 |
|
cat "$realpath" 1>&3 |
|
elif [ "$filepath" = "-" ]; then |
|
if [ -t 0 ]; then |
|
echo "Reading from stdin, press ^D to stop" |
|
else |
|
log "Reading from stdin" |
|
fi |
|
|
|
# preserve trailing newlines |
|
data=`cat; echo x` |
|
data=${data%x} |
|
filesize=$(echo -ne "$data" | wc -c) |
|
echo "data: $filesize" 1>&3 |
|
echo -n "$data" 1>&3 |
|
else |
|
echo "data: 0" 1>&3 |
|
fi |
|
|
|
echo 1>&3 |
|
} |
|
|
|
function handle_connection { |
|
local cmd |
|
local name |
|
local value |
|
local token |
|
local tmp |
|
|
|
while read 0<&3; do |
|
REPLY="${REPLY#"${REPLY%%[![:space:]]*}"}" |
|
REPLY="${REPLY%"${REPLY##*[![:space:]]}"}" |
|
|
|
cmd=$REPLY |
|
|
|
token="" |
|
tmp="" |
|
|
|
while read 0<&3; do |
|
REPLY="${REPLY#"${REPLY%%[![:space:]]*}"}" |
|
REPLY="${REPLY%"${REPLY##*[![:space:]]}"}" |
|
|
|
if [ "$REPLY" = "" ]; then |
|
break |
|
fi |
|
|
|
name="${REPLY%%:*}" |
|
value="${REPLY##*:}" |
|
value="${value#"${value%%[![:space:]]*}"}" # fix textmate syntax highlighting: " |
|
|
|
case $name in |
|
"token") |
|
token=$value |
|
;; |
|
"data") |
|
if [ "$tmp" = "" ]; then |
|
tmp="/tmp/rmate.$RANDOM.$$" |
|
touch "$tmp" |
|
fi |
|
|
|
dd bs=1 count=$value <&3 >>"$tmp" 2>/dev/null |
|
;; |
|
*) |
|
;; |
|
esac |
|
done |
|
|
|
if [[ "$cmd" = "close" ]]; then |
|
log "Closing $token" |
|
if [[ "$token" == "-" ]]; then |
|
echo -n "$CONTENT" |
|
fi |
|
if [[ "$nowait" != "" ]]; then |
|
printf "\e]1337;StealFocus\a" |
|
fi |
|
elif [[ "$cmd" = "save" ]]; then |
|
log "Saving $token" |
|
if "$force"; then |
|
# If nowait, then any save will restore focus |
|
if [[ "$nowait" = "" ]]; then |
|
printf "\e]1337;StealFocus\a" |
|
fi |
|
fi |
|
if [ "$token" != "-" ]; then |
|
cat "$tmp" > "$token" |
|
else |
|
CONTENT=`cat "$tmp"` |
|
fi |
|
rm "$tmp" |
|
fi |
|
done |
|
|
|
if "$force"; then |
|
printf "\e]1337;StealFocus\a" |
|
# khd -p 'cmd - tab' > /dev/null |
|
# khd -p '- return' > /dev/null |
|
fi |
|
|
|
log "Done" |
|
} |
|
|
|
# connect to textmate and send command |
|
# |
|
exec 3<> /dev/tcp/$host/$port |
|
|
|
if [ $? -gt 0 ]; then |
|
echo "Unable to connect to TextMate on $host:$port" |
|
exit 1 |
|
fi |
|
|
|
# Petonic 2017-04-30: Added the -c flag to check for RMATE server |
|
# connectivity |
|
if "$check_only"; then |
|
echo "check" 1>&3 |
|
exit 0 |
|
fi |
|
|
|
read server_info 0<&3 |
|
|
|
log $server_info |
|
|
|
for i in "${!filepaths[@]}"; do |
|
open_file "$i" |
|
done |
|
|
|
echo "." 1>&3 |
|
|
|
if [[ $nowait = true ]]; then |
|
exec </dev/null 2>/dev/null |
|
( (handle_connection &) &) |
|
else |
|
force=true |
|
handle_connection |
|
fi |