From 7db755dd68f3e8091460f51aad19f845dbb7b982 Mon Sep 17 00:00:00 2001 From: David Adam Date: Sun, 1 Dec 2013 18:09:50 +0800 Subject: [PATCH 01/11] Makefile.in: remove cruft --- Makefile.in | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Makefile.in b/Makefile.in index 6433eadeb..4f4dfb865 100644 --- a/Makefile.in +++ b/Makefile.in @@ -160,11 +160,6 @@ HDR_FILES := $(HDR_FILES_SRC:.hdr.in=.hdr) # Use a pattern rule so that Make knows to only issue one invocation # per http://www.gnu.org/software/make/manual/make.html#Pattern-Intro -# Internalized scripts are currently disabled. -# For now, we just generate empty arrays. -# To generate them again, you would run this: -# ./internalize_scripts.py share/functions/*.fish share/completions/*.fish - # # Files containing documentation for external commands. @@ -775,7 +770,6 @@ distclean: clean clean: rm -f *.o doc.h doc.tmp doc_src/*.doxygen doc_src/*.cpp doc_src/*.o doc_src/commands.hdr - rm -f $(GENERATED_INTERN_SCRIPT_FILES) rm -f tests/tmp.err tests/tmp.out tests/tmp.status tests/foo.txt rm -f $(PROGRAMS) fish_tests key_reader rm -f command_list.txt command_list_toc.txt toc.txt From f0946baeaaf75abcad3e0f7db939e98881560d18 Mon Sep 17 00:00:00 2001 From: David Adam Date: Mon, 2 Dec 2013 20:09:15 +0800 Subject: [PATCH 02/11] __fish_git_prompt: initialise colors early Otherwise __fish_git_prompt_informative_status tries to expand an unset variable. Closes #1157. --- share/functions/__fish_git_prompt.fish | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/share/functions/__fish_git_prompt.fish b/share/functions/__fish_git_prompt.fish index ba59c5fa8..0619a0972 100644 --- a/share/functions/__fish_git_prompt.fish +++ b/share/functions/__fish_git_prompt.fish @@ -371,6 +371,7 @@ function __fish_git_prompt --description "Prompt function for Git" set -l informative_status __fish_git_prompt_validate_chars + __fish_git_prompt_validate_colors if test "true" = $inside_worktree if test -n "$__fish_git_prompt_show_informative_status" @@ -403,8 +404,6 @@ function __fish_git_prompt --description "Prompt function for Git" end end - __fish_git_prompt_validate_colors - set -l branch_color $___fish_git_prompt_color_branch set -l branch_done $___fish_git_prompt_color_branch_done if test -n "$__fish_git_prompt_showcolorhints" From 0e7acaa3c4676dca7204deae85c08c2b2e426bb9 Mon Sep 17 00:00:00 2001 From: Tom Sutcliffe Date: Thu, 5 Dec 2013 10:38:42 +0000 Subject: [PATCH 03/11] Added completion for Android adb command. --- share/completions/adb.fish | 140 +++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 share/completions/adb.fish diff --git a/share/completions/adb.fish b/share/completions/adb.fish new file mode 100644 index 000000000..0eef3421f --- /dev/null +++ b/share/completions/adb.fish @@ -0,0 +1,140 @@ +# Completions for Android adb command + +function __fish_adb_no_subcommand --description 'Test if adb has yet to be given the subcommand' + for i in (commandline -opc) + if contains -- $i connect disconnect devices push pull sync shell emu logcat install uninstall jdwp forward bugreport backup restore version help wait-for-device start-server kill-server remount reboot get-state get-serialno get-devpath status-window root usb tcpip ppp + return 1 + end + end + return 0 +end + +function __fish_adb_get_devices --description 'Run adb devices and parse output' + # This seems reasonably portable for all the platforms adb runs on + set -l count (ps x | grep -c adb) + set -l TAB \t + # Don't run adb devices unless the server is already started - it takes a while to init + if [ $count -gt 1 ] + # The tail is to strip the header line, the sed is to massage the -l format + # into a simple "identifier modelname" format which is what we want for complete + adb devices -l | tail -n +2 | sed -E -e "s/([^ ]+) +./\1$TAB/" -e "s/$TAB.*model:([^ ]+).*/$TAB\1/" + end +end + +function __fish_adb_run_command --description 'Runs adb with any -s parameters already given on the command line' + set -l sopt + set -l sopt_is_next + set -l cmd (commandline -poc) + set -e cmd[1] + for i in $cmd + if test $sopt_is_next + set sopt -s $i + break + else + switch $i + case -s + set sopt_is_next 1 + end + end + end + + # If no -s option, see if there's a -d or -e instead + if test -z "$sopt" + if contains -- -d $cmd + set sopt '-d' + else if contains -- -e $cmd + set sopt '-e' + end + end + + # adb returns CRLF (seemingly) so strip CRs + adb $sopt shell $argv | sed s/\r// +end + +function __fish_adb_list_packages + __fish_adb_run_command pm list packages | sed s/package:// +end + + +function __fish_adb_list_uninstallable_packages + # -3 doesn't exactly mean show uninstallable, but it's the closest you can get to with pm list + __fish_adb_run_command pm list packages -3 | sed s/package:// +end + +# Generic options, must come before command +complete -n '__fish_adb_no_subcommand' -c adb -s s -x -a "(__fish_adb_get_devices)" -d 'Device to communicate with' +complete -n '__fish_adb_no_subcommand' -c adb -s d -d 'Communicate with first USB device' +complete -n '__fish_adb_no_subcommand' -c adb -s e -d 'Communicate with emulator' + +# Commands +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'connect' -d 'Connect to device' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'disconnect' -d 'Disconnect from device' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'devices' -d 'List all connected devices' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'push' -d 'Copy file to device' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'pull' -d 'Copy file from device' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'sync' -d 'Copy host->device only if changed' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'shell' -d 'Run remote shell [command]' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'emu' -d 'Run emulator console command' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'logcat' -d 'View device log' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'install' -d 'Install package' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'uninstall' -d 'Uninstall package' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'jdwp' -d 'List PIDs of processes hosting a JDWP transport' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'forward' -d 'Port forwarding' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'bugreport' -d 'Return bugreport information' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'backup' -d 'Perform device backup' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'restore' -d 'Restore device from backup' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'version' -d 'Show adb version' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'help' -d 'Show adb help' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'wait-for-device' -d 'Block until device is online' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'start-server' -d 'Ensure that there is a server running' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'kill-server' -d 'Kill the server if it is running' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'remount' -d 'Remounts the /system partition on the device read-write' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'reboot' -d 'Reboots the device, optionally into the bootloader or recovery program' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'get-state' -d 'Prints state of the device' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'get-serialno' -d 'Prints serial number of the device' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'get-devpath' -d 'Prints device path' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'status-window' -d 'Continuously print the device status' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'root' -d 'Restart the adbd daemon with root permissions' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'usb' -d 'Restart the adbd daemon listening on USB' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'tcpip' -d 'Restart the adbd daemon listening on TCP' +complete -f -n '__fish_adb_no_subcommand' -c adb -a 'ppp' -d 'Run PPP over USB' + +# install options +complete -n '__fish_seen_subcommand_from install' -c adb -s l -d 'Forward-lock the app' +complete -n '__fish_seen_subcommand_from install' -c adb -s r -d 'Reinstall the app keeping its data' +complete -n '__fish_seen_subcommand_from install' -c adb -s s -d 'Install on SD card instead of internal storage' +complete -n '__fish_seen_subcommand_from install' -c adb -l 'algo' -d 'Algorithm name' +complete -n '__fish_seen_subcommand_from install' -c adb -l 'key' -d 'Hex-encoded key' +complete -n '__fish_seen_subcommand_from install' -c adb -l 'iv' -d 'Hex-encoded iv' + +# uninstall +complete -n '__fish_seen_subcommand_from uninstall' -c adb -s k -d 'Keep the data and cache directories' +complete -n '__fish_seen_subcommand_from uninstall' -c adb -f -u -a "(__fish_adb_list_uninstallable_packages)" + +# devices +complete -n '__fish_seen_subcommand_from devices' -c adb -s l -d 'Also list device qualifiers' + +# disconnect +complete -n '__fish_seen_subcommand_from disconnect' -c adb -x -a "(__fish_adb_get_devices)" -d 'Device to disconnect' + +# backup +complete -n '__fish_seen_subcommand_from backup' -c adb -s f -d 'File to write backup data to' +complete -n '__fish_seen_subcommand_from backup' -c adb -o 'apk' -d 'Enable backup of the .apks themselves' +complete -n '__fish_seen_subcommand_from backup' -c adb -o 'noapk' -d 'Disable backup of the .apks themselves (default)' +complete -n '__fish_seen_subcommand_from backup' -c adb -o 'obb' -d 'Enable backup of any installed apk expansion' +complete -n '__fish_seen_subcommand_from backup' -c adb -o 'noobb' -d 'Disable backup of any installed apk expansion (default)' +complete -n '__fish_seen_subcommand_from backup' -c adb -o 'shared' -d 'Enable backup of the device\'s shared storage / SD card contents' +complete -n '__fish_seen_subcommand_from backup' -c adb -o 'noshared' -d 'Disable backup of the device\'s shared storage / SD card contents (default)' +complete -n '__fish_seen_subcommand_from backup' -c adb -o 'all' -d 'Back up all installed applications' +complete -n '__fish_seen_subcommand_from backup' -c adb -o 'system' -d 'Include system applications in -all (default)' +complete -n '__fish_seen_subcommand_from backup' -c adb -o 'nosystem' -d 'Exclude system applications in -all' +complete -n '__fish_seen_subcommand_from backup' -c adb -f -a "(__fish_adb_list_packages)" -d 'Package(s) to backup' + +# reboot +complete -n '__fish_seen_subcommand_from reboot' -c adb -x -a 'bootloader recovery' + +# forward +complete -n '__fish_seen_subcommand_from forward' -c adb -l 'list' -d 'List all forward socket connections' +complete -n '__fish_seen_subcommand_from forward' -c adb -l 'no-rebind' -d 'Fails the forward if local is already forwarded' +complete -n '__fish_seen_subcommand_from forward' -c adb -l 'remove' -d 'Remove a specific forward socket connection' +complete -n '__fish_seen_subcommand_from forward' -c adb -l 'remove-all' -d 'Remove all forward socket connections' From 9bbda857c33d25450c57f55842d733a0b185687e Mon Sep 17 00:00:00 2001 From: Jay Weisskopf Date: Tue, 10 Dec 2013 12:52:04 -0500 Subject: [PATCH 04/11] Prepend user paths even if they already exist in system path Fixes #1099 --- share/config.fish | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/share/config.fish b/share/config.fish index 6b62a01c3..5eac39bf3 100644 --- a/share/config.fish +++ b/share/config.fish @@ -89,10 +89,12 @@ function __fish_reconstruct_path -d "Update PATH when fish_user_paths changes" - set -e __fish_added_user_paths for x in $fish_user_paths[-1..1] - if not contains $x $local_path - set local_path $x $local_path + if set -l idx (contains --index $x $local_path) + set -e local_path[$idx] + else set -g __fish_added_user_paths $__fish_added_user_paths $x end + set local_path $x $local_path end set -xg PATH $local_path end From 0ec97c5d1e0ba812a596dc0e3a675d51746ca9c9 Mon Sep 17 00:00:00 2001 From: Thomas Cort Date: Sat, 7 Dec 2013 20:45:52 -0500 Subject: [PATCH 05/11] doc_src/eval.txt: fix typo. 'folloing' => 'following' --- doc_src/eval.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc_src/eval.txt b/doc_src/eval.txt index 0227255a0..f8af8f666 100644 --- a/doc_src/eval.txt +++ b/doc_src/eval.txt @@ -8,7 +8,7 @@ \subsection eval-example Example -The folloing code will call the ls command. Note that \c fish does not +The following code will call the ls command. Note that \c fish does not support the use of environment variables as direct commands; \c eval can be used to work around this. From 602f040940b03e995928a45fc2cb70088a84c091 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Fri, 13 Dec 2013 21:51:52 +0100 Subject: [PATCH 06/11] Update Free Software Foundation address. Fixes #1184. --- Makefile.in | 2 +- doc_src/license.hdr | 4 ++-- fish.cpp | 2 +- fish_indent.cpp | 2 +- xdgmime.cpp | 4 ++-- xdgmime.h | 4 ++-- xdgmimealias.cpp | 4 ++-- xdgmimealias.h | 4 ++-- xdgmimeglob.cpp | 4 ++-- xdgmimeglob.h | 4 ++-- xdgmimeint.cpp | 4 ++-- xdgmimeint.h | 4 ++-- xdgmimemagic.cpp | 4 ++-- xdgmimemagic.h | 4 ++-- xdgmimeparent.cpp | 4 ++-- xdgmimeparent.h | 4 ++-- 16 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Makefile.in b/Makefile.in index 4f4dfb865..b81206d40 100644 --- a/Makefile.in +++ b/Makefile.in @@ -11,7 +11,7 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # # diff --git a/doc_src/license.hdr b/doc_src/license.hdr index 64bab10f0..c07a94ad2 100644 --- a/doc_src/license.hdr +++ b/doc_src/license.hdr @@ -17,7 +17,7 @@ Version 2, June 1991
 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.
@@ -995,7 +995,7 @@ Version 2, June 1991
 
 
 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.
diff --git a/fish.cpp b/fish.cpp
index ca5d50e90..57d268d72 100644
--- a/fish.cpp
+++ b/fish.cpp
@@ -12,7 +12,7 @@ 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, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */
 
 
diff --git a/fish_indent.cpp b/fish_indent.cpp
index c4d6d81cd..4560bb961 100644
--- a/fish_indent.cpp
+++ b/fish_indent.cpp
@@ -12,7 +12,7 @@ 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, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */
 
 
diff --git a/xdgmime.cpp b/xdgmime.cpp
index 39d0a1894..633d0b0a5 100644
--- a/xdgmime.cpp
+++ b/xdgmime.cpp
@@ -21,8 +21,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA
  */
 
 #ifdef HAVE_CONFIG_H
diff --git a/xdgmime.h b/xdgmime.h
index b552be7b7..9c53bb11a 100644
--- a/xdgmime.h
+++ b/xdgmime.h
@@ -21,8 +21,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA
  */
 
 
diff --git a/xdgmimealias.cpp b/xdgmimealias.cpp
index 05a5e3579..e556d4e64 100644
--- a/xdgmimealias.cpp
+++ b/xdgmimealias.cpp
@@ -21,8 +21,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
diff --git a/xdgmimealias.h b/xdgmimealias.h
index 384d12769..13933642d 100644
--- a/xdgmimealias.h
+++ b/xdgmimealias.h
@@ -21,8 +21,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
  */
 
 #ifndef __XDG_MIME_ALIAS_H__
diff --git a/xdgmimeglob.cpp b/xdgmimeglob.cpp
index 49d098bf0..4182f3c97 100644
--- a/xdgmimeglob.cpp
+++ b/xdgmimeglob.cpp
@@ -21,8 +21,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
diff --git a/xdgmimeglob.h b/xdgmimeglob.h
index 7f2ea1d3f..136e49a39 100644
--- a/xdgmimeglob.h
+++ b/xdgmimeglob.h
@@ -21,8 +21,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
  */
 
 #ifndef __XDG_MIME_GLOB_H__
diff --git a/xdgmimeint.cpp b/xdgmimeint.cpp
index a7847141a..7e8ea31ca 100644
--- a/xdgmimeint.cpp
+++ b/xdgmimeint.cpp
@@ -21,8 +21,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
diff --git a/xdgmimeint.h b/xdgmimeint.h
index 33116df1d..5e825dab3 100644
--- a/xdgmimeint.h
+++ b/xdgmimeint.h
@@ -21,8 +21,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
  */
 
 #ifndef __XDG_MIME_INT_H__
diff --git a/xdgmimemagic.cpp b/xdgmimemagic.cpp
index 8bcca9488..aecca8822 100644
--- a/xdgmimemagic.cpp
+++ b/xdgmimemagic.cpp
@@ -21,8 +21,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
diff --git a/xdgmimemagic.h b/xdgmimemagic.h
index 61e9d20db..1a747583a 100644
--- a/xdgmimemagic.h
+++ b/xdgmimemagic.h
@@ -21,8 +21,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
  */
 
 #ifndef __XDG_MIME_MAGIC_H__
diff --git a/xdgmimeparent.cpp b/xdgmimeparent.cpp
index 3e51c295c..d0fa617dc 100644
--- a/xdgmimeparent.cpp
+++ b/xdgmimeparent.cpp
@@ -21,8 +21,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
diff --git a/xdgmimeparent.h b/xdgmimeparent.h
index 9baf44a3e..ca6e85267 100644
--- a/xdgmimeparent.h
+++ b/xdgmimeparent.h
@@ -21,8 +21,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
  */
 
 #ifndef __XDG_MIME_PARENT_H__

From d61adfbc532e856242730e198e492a2845754a91 Mon Sep 17 00:00:00 2001
From: Konrad Borowski 
Date: Sun, 15 Dec 2013 11:00:03 +0100
Subject: [PATCH 07/11] Ensure that UTF-8 works if LANG contains it.

Some people like to have their terminals claim UTF-8 support when
their terminals actually are set to another encoding. As nobody
appears to understand this, I have made a change to automatically
fix the encoding problems if possible. This uses ISO 2022 sequences
in order to dynamically change the encoding.

Fixes #692. Fixes #895. Fixes possible future issues about this.
---
 share/config.fish | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/share/config.fish b/share/config.fish
index 5eac39bf3..14b914460 100644
--- a/share/config.fish
+++ b/share/config.fish
@@ -130,3 +130,13 @@ function . --description 'Evaluate contents of file (deprecated, see "source")'
 		source $argv
 	end
 end
+
+# Fix lame terminals lying about their encoding (UTF-8 when it's not).
+function __fish_update_charset --on-variable LANG
+	switch $LANG
+		case \*.UTF-8
+			echo -n \e%G
+	end
+end
+
+__fish_update_charset

From 5c96bca1ca5340563bdcbb766a5b4161d269fb6f Mon Sep 17 00:00:00 2001
From: Konrad Borowski 
Date: Tue, 17 Dec 2013 20:47:14 +0100
Subject: [PATCH 08/11] Revert "Ensure that UTF-8 works if LANG contains it."

This was a really stupid change that I should have tested more
before pushing. It broke any non-interactive usage, such as SSH,
fish config, or parsing the script output, as config.fish is
loaded for everything.

There are no issues with different terminal emulators, so this
change will be pushed in the future, but only running in interactive
mode. I apologize for any issues caused by this commit.

This reverts commit d61adfbc532e856242730e198e492a2845754a91.
---
 share/config.fish | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/share/config.fish b/share/config.fish
index 14b914460..5eac39bf3 100644
--- a/share/config.fish
+++ b/share/config.fish
@@ -130,13 +130,3 @@ function . --description 'Evaluate contents of file (deprecated, see "source")'
 		source $argv
 	end
 end
-
-# Fix lame terminals lying about their encoding (UTF-8 when it's not).
-function __fish_update_charset --on-variable LANG
-	switch $LANG
-		case \*.UTF-8
-			echo -n \e%G
-	end
-end
-
-__fish_update_charset

From 8bcb5e4ed7e93d0a7eac2cb7ab70b0e69b965ae5 Mon Sep 17 00:00:00 2001
From: Mandeep Sandhu 
Date: Wed, 18 Dec 2013 16:57:20 +0530
Subject: [PATCH 09/11] Ignore auto-generated file command_list_toc.txt

Added this file to the ignore list (Issue #1192).
---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index b55ce1e23..b587873d4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ Makefile
 autom4te.cache/
 build/
 command_list.txt
+command_list_toc.txt
 confdefs.h
 config.h
 config.h.in

From 12be83562d9096538848a554c4d9f0e0f30f760f Mon Sep 17 00:00:00 2001
From: Javier Gonel 
Date: Wed, 18 Dec 2013 18:02:19 +0200
Subject: [PATCH 10/11] Non standard cut options

Some cut versions don't have `--delimiter` or `--fields` but use the standard options `-d` and `-f`
---
 share/functions/__fish_print_svn_rev.fish | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/share/functions/__fish_print_svn_rev.fish b/share/functions/__fish_print_svn_rev.fish
index 7b8638dca..cbc3770a3 100644
--- a/share/functions/__fish_print_svn_rev.fish
+++ b/share/functions/__fish_print_svn_rev.fish
@@ -1,5 +1,5 @@
 function __fish_print_svn_rev --description 'Print svn revisions'
-	svn info | grep "Last Changed Rev" | cut --delimiter " " --fields 4
+	svn info | grep "Last Changed Rev" | cut -d " " -f 4
 	echo \{\tRevision at start of the date
 	echo HEAD\tLatest in repository
 	echo BASE\tBase rev of item\'s working copy

From e38217683c65f53fcaa3b6a5daedb6b23b408a90 Mon Sep 17 00:00:00 2001
From: ridiculousfish 
Date: Fri, 20 Dec 2013 17:41:21 -0800
Subject: [PATCH 11/11] Refactor block_t storage in parser_t from a linked list
 to a vector

---
 builtin.cpp  | 160 +++++++++++++++++++++--------------------
 event.cpp    |   7 +-
 exec.cpp     |   3 +-
 function.cpp |   2 +-
 parser.cpp   | 196 +++++++++++++++++++++++++++------------------------
 parser.h     |  28 +++++---
 reader.cpp   |   9 +--
 7 files changed, 218 insertions(+), 187 deletions(-)

diff --git a/builtin.cpp b/builtin.cpp
index c1281a529..a57218900 100644
--- a/builtin.cpp
+++ b/builtin.cpp
@@ -831,7 +831,8 @@ static int builtin_block(parser_t &parser, wchar_t **argv)
     }
     else
     {
-        block_t *block=parser.current_block;
+        size_t block_idx = 0;
+        block_t *block = parser.block_at_index(block_idx);
 
         event_blockage_t eb = {};
         eb.typemask = type;
@@ -840,20 +841,24 @@ static int builtin_block(parser_t &parser, wchar_t **argv)
         {
             case LOCAL:
             {
-                if (!block->outer)
-                    block=0;
+                // If this is the outermost block, then we're global
+                if (block_idx + 1 >= parser.block_count())
+                {
+                    block = NULL;
+                }
                 break;
             }
             case GLOBAL:
             {
-                block=0;
+                block=NULL;
             }
             case UNSET:
             {
-                while (block &&
-                        block->type() != FUNCTION_CALL &&
-                        block->type() != FUNCTION_CALL_NO_SHADOW)
-                    block = block->outer;
+                while (block != NULL && block->type() != FUNCTION_CALL && block->type() != FUNCTION_CALL_NO_SHADOW)
+                {
+                    // Set it in function scope
+                    block = parser.block_at_index(++block_idx);
+                }
             }
         }
         if (block)
@@ -1863,18 +1868,21 @@ static int builtin_function(parser_t &parser, wchar_t **argv)
 
                     if (is_subshell)
                     {
-                        block_t *b = parser.current_block;
-
-                        while (b && (b->type() != SUBST))
-                            b = b->outer;
-
-                        if (b)
+                        size_t block_idx = 0;
+                        
+                        /* Find the outermost substitution block */
+                        for (block_idx = 0; ; block_idx++)
                         {
-                            b=b->outer;
+                            const block_t *b = parser.block_at_index(block_idx);
+                            if (b == NULL || b->type() == SUBST)
+                                break;
                         }
-                        if (b->job)
+                        
+                        /* Go one step beyond that, to get to the caller */
+                        const block_t *caller_block = parser.block_at_index(block_idx + 1);
+                        if (caller_block != NULL && caller_block->job != NULL)
                         {
-                            job_id = b->job->job_id;
+                            job_id = caller_block->job->job_id;
                         }
                     }
 
@@ -2058,8 +2066,8 @@ static int builtin_function(parser_t &parser, wchar_t **argv)
         }
     }
 
-    parser.current_block->tok_pos = parser.get_pos();
-    parser.current_block->skip = 1;
+    parser.current_block()->tok_pos = parser.get_pos();
+    parser.current_block()->skip = 1;
 
     return STATUS_BUILTIN_OK;
 }
@@ -2712,7 +2720,7 @@ static int builtin_status(parser_t &parser, wchar_t **argv)
 
             case STACK_TRACE:
             {
-                parser.stack_trace(parser.current_block, stdout_buffer);
+                parser.stack_trace(0, stdout_buffer);
                 break;
             }
 
@@ -2727,7 +2735,7 @@ static int builtin_status(parser_t &parser, wchar_t **argv)
                               job_control_mode==JOB_CONTROL_INTERACTIVE?_(L"Only on interactive jobs"):
                               (job_control_mode==JOB_CONTROL_NONE ? _(L"Never") : _(L"Always")));
 
-                parser.stack_trace(parser.current_block, stdout_buffer);
+                parser.stack_trace(0, stdout_buffer);
                 break;
             }
         }
@@ -3413,19 +3421,19 @@ static int builtin_for(parser_t &parser, wchar_t **argv)
         }
         else
         {
-            parser.current_block->skip=1;
+            parser.current_block()->skip=1;
         }
     }
     return res;
 }
 
 /**
-   The begin builtin. Creates a nex block.
+   The begin builtin. Creates a new block.
 */
 static int builtin_begin(parser_t &parser, wchar_t **argv)
 {
     parser.push_block(new scope_block_t(BEGIN));
-    parser.current_block->tok_pos = parser.get_pos();
+    parser.current_block()->tok_pos = parser.get_pos();
     return proc_get_last_status();
 }
 
@@ -3437,7 +3445,7 @@ static int builtin_begin(parser_t &parser, wchar_t **argv)
 */
 static int builtin_end(parser_t &parser, wchar_t **argv)
 {
-    if (!parser.current_block->outer)
+    if (! parser.block_at_index(1))
     {
         append_format(stderr_buffer,
                       _(L"%ls: Not inside of block\n"),
@@ -3455,7 +3463,8 @@ static int builtin_end(parser_t &parser, wchar_t **argv)
         */
         bool kill_block = true;
 
-        switch (parser.current_block->type())
+        block_t * const current_block = parser.current_block();
+        switch (current_block->type())
         {
             case WHILE:
             {
@@ -3463,13 +3472,13 @@ static int builtin_end(parser_t &parser, wchar_t **argv)
                   If this is a while loop, we rewind the loop unless
                   it's the last lap, in which case we continue.
                 */
-                if (!(parser.current_block->skip && (parser.current_block->loop_status != LOOP_CONTINUE)))
+                if (!(current_block->skip && (current_block->loop_status != LOOP_CONTINUE)))
                 {
-                    parser.current_block->loop_status = LOOP_NORMAL;
-                    parser.current_block->skip = 0;
+                    current_block->loop_status = LOOP_NORMAL;
+                    current_block->skip = 0;
                     kill_block = false;
-                    parser.set_pos(parser.current_block->tok_pos);
-                    while_block_t *blk = static_cast(parser.current_block);
+                    parser.set_pos(current_block->tok_pos);
+                    while_block_t *blk = static_cast(current_block);
                     blk->status = WHILE_TEST_AGAIN;
                 }
 
@@ -3492,9 +3501,9 @@ static int builtin_end(parser_t &parser, wchar_t **argv)
                 /*
                   set loop variable to next element, and rewind to the beginning of the block.
                 */
-                for_block_t *fb = static_cast(parser.current_block);
+                for_block_t *fb = static_cast(current_block);
                 wcstring_list_t &for_vars = fb->sequence;
-                if (parser.current_block->loop_status == LOOP_BREAK)
+                if (current_block->loop_status == LOOP_BREAK)
                 {
                     for_vars.clear();
                 }
@@ -3505,18 +3514,18 @@ static int builtin_end(parser_t &parser, wchar_t **argv)
                     for_vars.pop_back();
                     const wcstring &for_variable = fb->variable;
                     env_set(for_variable, val.c_str(),  ENV_LOCAL);
-                    parser.current_block->loop_status = LOOP_NORMAL;
-                    parser.current_block->skip = 0;
+                    current_block->loop_status = LOOP_NORMAL;
+                    current_block->skip = 0;
 
                     kill_block = false;
-                    parser.set_pos(parser.current_block->tok_pos);
+                    parser.set_pos(current_block->tok_pos);
                 }
                 break;
             }
 
             case FUNCTION_DEF:
             {
-                function_def_block_t *fdb = static_cast(parser.current_block);
+                function_def_block_t *fdb = static_cast(current_block);
                 function_data_t &d = fdb->function_data;
 
                 if (d.name.empty())
@@ -3535,8 +3544,8 @@ static int builtin_end(parser_t &parser, wchar_t **argv)
                        for the specified function
                     */
 
-                    wchar_t *def = wcsndup(parser.get_buffer()+parser.current_block->tok_pos,
-                                           parser.get_job_pos()-parser.current_block->tok_pos);
+                    wchar_t *def = wcsndup(parser.get_buffer()+current_block->tok_pos,
+                                           parser.get_job_pos()-current_block->tok_pos);
                     d.definition = def;
 
                     function_add(d, parser);
@@ -3569,9 +3578,9 @@ static int builtin_else(parser_t &parser, wchar_t **argv)
 {
     bool block_ok = false;
     if_block_t *if_block = NULL;
-    if (parser.current_block != NULL && parser.current_block->type() == IF)
+    if (parser.current_block() != NULL && parser.current_block()->type() == IF)
     {
-        if_block = static_cast(parser.current_block);
+        if_block = static_cast(parser.current_block());
         /* Ensure that we're past IF but not up to an ELSE */
         if (if_block->if_expr_evaluated && ! if_block->else_evaluated)
         {
@@ -3612,7 +3621,6 @@ static int builtin_break_continue(parser_t &parser, wchar_t **argv)
     int is_break = (wcscmp(argv[0],L"break")==0);
     int argc = builtin_count_args(argv);
 
-    block_t *b = parser.current_block;
 
     if (argc != 1)
     {
@@ -3625,15 +3633,16 @@ static int builtin_break_continue(parser_t &parser, wchar_t **argv)
         return STATUS_BUILTIN_ERROR;
     }
 
-
-    while ((b != 0) &&
-            (b->type() != WHILE) &&
-            (b->type() != FOR))
+    /* Find the index of the enclosing for or while loop. Recall that incrementing loop_idx goes 'up' to outer blocks */
+    size_t loop_idx;
+    for (loop_idx = 0; loop_idx < parser.block_count(); loop_idx++)
     {
-        b = b->outer;
+        const block_t *b = parser.block_at_index(loop_idx);
+        if (b->type() == WHILE || b->type() == FOR)
+            break;
     }
 
-    if (b == 0)
+    if (loop_idx >= parser.block_count())
     {
         append_format(stderr_buffer,
                       _(L"%ls: Not inside of loop\n"),
@@ -3642,15 +3651,17 @@ static int builtin_break_continue(parser_t &parser, wchar_t **argv)
         return STATUS_BUILTIN_ERROR;
     }
 
-    b = parser.current_block;
-    while ((b->type() != WHILE) &&
-            (b->type() != FOR))
+    /* Skip blocks interior to the loop  */
+    size_t block_idx = loop_idx;
+    while (block_idx--)
     {
-        b->skip=1;
-        b = b->outer;
+        parser.block_at_index(block_idx)->skip = true;
     }
-    b->skip=1;
-    b->loop_status = is_break?LOOP_BREAK:LOOP_CONTINUE;
+    
+    /* Skip the loop itself */
+    block_t *loop_block = parser.block_at_index(loop_idx);
+    loop_block->skip = true;
+    loop_block->loop_status = is_break ? LOOP_BREAK : LOOP_CONTINUE;
     return STATUS_BUILTIN_OK;
 }
 
@@ -3679,8 +3690,6 @@ static int builtin_return(parser_t &parser, wchar_t **argv)
     int argc = builtin_count_args(argv);
     int status = proc_get_last_status();
 
-    block_t *b = parser.current_block;
-
     switch (argc)
     {
         case 1:
@@ -3709,15 +3718,16 @@ static int builtin_return(parser_t &parser, wchar_t **argv)
             return STATUS_BUILTIN_ERROR;
     }
 
-
-    while ((b != 0) &&
-            (b->type() != FUNCTION_CALL &&
-             b->type() != FUNCTION_CALL_NO_SHADOW))
+    /* Find the function block */
+    size_t function_block_idx;
+    for (function_block_idx = 0; function_block_idx < parser.block_count(); function_block_idx++)
     {
-        b = b->outer;
+        const block_t *b = parser.block_at_index(function_block_idx);
+        if (b->type() == FUNCTION_CALL || b->type() == FUNCTION_CALL_NO_SHADOW)
+            break;
     }
 
-    if (b == 0)
+    if (function_block_idx >= parser.block_count())
     {
         append_format(stderr_buffer,
                       _(L"%ls: Not inside of function\n"),
@@ -3725,17 +3735,15 @@ static int builtin_return(parser_t &parser, wchar_t **argv)
         builtin_print_help(parser, argv[0], stderr_buffer);
         return STATUS_BUILTIN_ERROR;
     }
-
-    b = parser.current_block;
-    while ((b->type() != FUNCTION_CALL &&
-            b->type() != FUNCTION_CALL_NO_SHADOW))
+    
+    /* Skip everything up to (and then including) the function block */
+    for (size_t i=0; i < function_block_idx; i++)
     {
+        block_t *b = parser.block_at_index(i);
         b->mark_as_fake();
-        b->skip=1;
-        b = b->outer;
+        b->skip = true;
     }
-    b->skip=1;
-
+    parser.block_at_index(function_block_idx)->skip = true;
     return status;
 }
 
@@ -3762,7 +3770,7 @@ static int builtin_switch(parser_t &parser, wchar_t **argv)
     else
     {
         parser.push_block(new switch_block_t(argv[1]));
-        parser.current_block->skip=1;
+        parser.current_block()->skip=1;
         res = proc_get_last_status();
     }
 
@@ -3779,7 +3787,7 @@ static int builtin_case(parser_t &parser, wchar_t **argv)
     int i;
     wchar_t *unescaped=0;
 
-    if (parser.current_block->type() != SWITCH)
+    if (parser.current_block()->type() != SWITCH)
     {
         append_format(stderr_buffer,
                       _(L"%ls: 'case' command while not in switch block\n"),
@@ -3788,8 +3796,8 @@ static int builtin_case(parser_t &parser, wchar_t **argv)
         return STATUS_BUILTIN_ERROR;
     }
 
-    parser.current_block->skip = 1;
-    switch_block_t *sb = static_cast(parser.current_block);
+    parser.current_block()->skip = 1;
+    switch_block_t *sb = static_cast(parser.current_block());
     if (sb->switch_taken)
     {
         return proc_get_last_status();
@@ -3806,7 +3814,7 @@ static int builtin_case(parser_t &parser, wchar_t **argv)
 
         if (match)
         {
-            parser.current_block->skip = 0;
+            parser.current_block()->skip = 0;
             sb->switch_taken = true;
             break;
         }
diff --git a/event.cpp b/event.cpp
index f6313fb0c..d2b219e7d 100644
--- a/event.cpp
+++ b/event.cpp
@@ -144,12 +144,15 @@ static int event_match(const event_t &classv, const event_t &instance)
 */
 static int event_is_blocked(const event_t &e)
 {
-    block_t *block;
+    const block_t *block;
     parser_t &parser = parser_t::principal_parser();
-    for (block = parser.current_block; block; block = block->outer)
+    
+    size_t idx = 0;
+    while ((block = parser.block_at_index(idx++)))
     {
         if (event_block_list_blocks_type(block->event_blocks, e.type))
             return true;
+        
     }
     return event_block_list_blocks_type(parser.global_event_blocks, e.type);
 }
diff --git a/exec.cpp b/exec.cpp
index b894ce690..6d7a19e88 100644
--- a/exec.cpp
+++ b/exec.cpp
@@ -580,7 +580,8 @@ static void exec_no_exec(parser_t &parser, const job_t *job)
             }
             else if (builtin_name == L"end")
             {
-                if (parser.current_block == NULL || parser.current_block->type() == TOP)
+                const block_t *block = parser.current_block();
+                if (block == NULL || block->type() == TOP)
                 {
                     fprintf(stderr, "Warning: not popping the root block\n");
                 }
diff --git a/function.cpp b/function.cpp
index da7574d39..c559a686a 100644
--- a/function.cpp
+++ b/function.cpp
@@ -189,7 +189,7 @@ void function_add(const function_data_t &data, const parser_t &parser)
 
     /* Create and store a new function */
     const wchar_t *filename = reader_current_filename();
-    int def_offset = parser.line_number_of_character_at_offset(parser.current_block->tok_pos) - 1;
+    int def_offset = parser.line_number_of_character_at_offset(parser.current_block()->tok_pos) - 1;
     const function_map_t::value_type new_pair(data.name, function_info_t(data, filename, def_offset, is_autoload));
     loaded_functions.insert(new_pair);
 
diff --git a/parser.cpp b/parser.cpp
index 328e331a9..62b45dcc3 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -325,7 +325,6 @@ parser_t::parser_t(enum parser_type_t type, bool errors) :
     current_tokenizer_pos(0),
     job_start_pos(0),
     eval_level(-1),
-    current_block(NULL),
     block_io(shared_ptr())
 {
 
@@ -352,39 +351,36 @@ void parser_t::skip_all_blocks(void)
     if (s_principal_parser)
     {
         //write(2, "Cancelling blocks\n", strlen("Cancelling blocks\n"));
-        block_t *c = s_principal_parser->current_block;
-        while (c)
+        for (size_t i=0; i < s_principal_parser->block_count(); i++)
         {
-            c->skip = true;
-            //fprintf(stderr, "   Cancelled %p\n", c);
-            c = c->outer;
+            s_principal_parser->block_at_index(i)->skip = true;
         }
     }
 }
 
-void parser_t::push_block(block_t *newv)
+void parser_t::push_block(block_t *new_current)
 {
-    const enum block_type_t type = newv->type();
-    newv->src_lineno = parser_t::get_lineno();
-    newv->src_filename = parser_t::current_filename()?intern(parser_t::current_filename()):0;
+    const enum block_type_t type = new_current->type();
+    new_current->src_lineno = parser_t::get_lineno();
+    new_current->src_filename = parser_t::current_filename()?intern(parser_t::current_filename()):0;
 
-    newv->outer = current_block;
-    if (current_block && current_block->skip)
-        newv->mark_as_fake();
+    const block_t *old_current = this->current_block();
+    if (old_current && old_current->skip)
+        new_current->mark_as_fake();
 
     /*
       New blocks should be skipped if the outer block is skipped,
       except TOP ans SUBST block, which open up new environments. Fake
       blocks should always be skipped. Rather complicated... :-(
     */
-    newv->skip=current_block?current_block->skip:0;
+    new_current->skip = old_current ? old_current->skip : 0;
 
     /*
       Type TOP and SUBST are never skipped
     */
     if (type == TOP || type == SUBST)
     {
-        newv->skip = 0;
+        new_current->skip = 0;
     }
 
     /*
@@ -392,27 +388,26 @@ void parser_t::push_block(block_t *newv)
     */
     if (type == FAKE || type == FUNCTION_DEF)
     {
-        newv->skip = 1;
+        new_current->skip = 1;
     }
 
-    newv->job = 0;
-    newv->loop_status=LOOP_NORMAL;
+    new_current->job = 0;
+    new_current->loop_status=LOOP_NORMAL;
+    
+    this->block_stack.push_back(new_current);
 
-    current_block = newv;
-
-    if ((newv->type() != FUNCTION_DEF) &&
-            (newv->type() != FAKE) &&
-            (newv->type() != TOP))
+    if ((new_current->type() != FUNCTION_DEF) &&
+            (new_current->type() != FAKE) &&
+            (new_current->type() != TOP))
     {
         env_push(type == FUNCTION_CALL);
-        newv->wants_pop_env = true;
+        new_current->wants_pop_env = true;
     }
 }
 
 void parser_t::pop_block()
 {
-    block_t *old = current_block;
-    if (!current_block)
+    if (block_stack.empty())
     {
         debug(1,
               L"function %s called on empty block stack.",
@@ -421,7 +416,8 @@ void parser_t::pop_block()
         return;
     }
 
-    current_block = current_block->outer;
+    block_t *old = block_stack.back();
+    block_stack.pop_back();
 
     if (old->wants_pop_env)
         env_pop();
@@ -441,6 +437,30 @@ const wchar_t *parser_t::get_block_desc(int block) const
     return _(UNKNOWN_BLOCK);
 }
 
+const block_t *parser_t::block_at_index(size_t idx) const
+{
+    /* 0 corresponds to the last element in our vector */
+    size_t count = block_stack.size();
+    return idx < count ? block_stack.at(count - idx - 1) : NULL;
+}
+
+block_t *parser_t::block_at_index(size_t idx)
+{
+    size_t count = block_stack.size();
+    return idx < count ? block_stack.at(count - idx - 1) : NULL;
+}
+
+const block_t *parser_t::current_block() const
+{
+    return block_stack.empty() ? NULL : block_stack.back();
+}
+
+block_t *parser_t::current_block()
+{
+    return block_stack.empty() ? NULL : block_stack.back();
+}
+
+
 /**
    Returns 1 if the specified command is a builtin that may not be used in a pipeline
 */
@@ -807,13 +827,15 @@ int parser_t::eval_args(const wchar_t *line, std::vector &args)
     return 1;
 }
 
-void parser_t::stack_trace(block_t *b, wcstring &buff)
+void parser_t::stack_trace(size_t block_idx, wcstring &buff)
 {
     /*
       Check if we should end the recursion
     */
-    if (!b)
+    if (block_idx >= this->block_count())
         return;
+    
+    const block_t *b = this->block_at_index(block_idx);
 
     if (b->type()==EVENT)
     {
@@ -908,7 +930,7 @@ void parser_t::stack_trace(block_t *b, wcstring &buff)
     /*
       Recursively print the next block
     */
-    parser_t::stack_trace(b->outer, buff);
+    parser_t::stack_trace(block_idx + 1, buff);
 }
 
 /**
@@ -921,22 +943,19 @@ const wchar_t *parser_t::is_function() const
 {
     // PCA: Have to make this a string somehow
     ASSERT_IS_MAIN_THREAD();
-    wcstring result;
 
-    block_t *b = current_block;
-    while (1)
+    const wchar_t *result = NULL;
+    for (size_t block_idx = 0; block_idx < this->block_count(); block_idx++)
     {
-        if (!b)
-        {
-            return NULL;
-        }
+        const block_t *b = this->block_at_index(block_idx);
         if (b->type() == FUNCTION_CALL)
         {
             const function_block_t *fb = static_cast(b);
-            return fb->name.c_str();
+            result = fb->name.c_str();
+            break;
         }
-        b=b->outer;
     }
+    return result;
 }
 
 
@@ -974,21 +993,17 @@ const wchar_t *parser_t::current_filename() const
     ASSERT_IS_MAIN_THREAD();
     assert(this == &principal_parser());
 
-    block_t *b = current_block;
 
-    while (1)
+    for (size_t i=0; i < this->block_count(); i++)
     {
-        if (!b)
-        {
-            return reader_current_filename();
-        }
+        const block_t *b = this->block_at_index(i);
         if (b->type() == FUNCTION_CALL)
         {
             const function_block_t *fb = static_cast(b);
             return function_get_definition_file(fb->name);
         }
-        b=b->outer;
     }
+    return reader_current_filename();
 }
 
 /**
@@ -1129,7 +1144,7 @@ const wchar_t *parser_t::current_line()
     }
 
     free((void *)line);
-    parser_t::stack_trace(current_block, lineinfo);
+    parser_t::stack_trace(0, lineinfo);
 
     return lineinfo.c_str();
 }
@@ -1239,7 +1254,7 @@ job_t *parser_t::job_get_from_pid(int pid)
    \param j the job to which the process belongs to
    \param tok the tokenizer to read options from
    \param args the argument list to insert options into
-   \param args unskip whether we should ignore current_block->skip. Big hack because of our dumb handling of if statements.
+   \param args unskip whether we should ignore current_block()->skip. Big hack because of our dumb handling of if statements.
 */
 void parser_t::parse_job_argument_list(process_t *p,
                                        job_t *j,
@@ -1336,7 +1351,7 @@ void parser_t::parse_job_argument_list(process_t *p,
                 {
                     skip = 1;
                 }
-                else if (current_block->skip && ! unskip)
+                else if (current_block()->skip && ! unskip)
                 {
                     /*
                       If this command should be skipped, we do not expand the arguments
@@ -1344,12 +1359,12 @@ void parser_t::parse_job_argument_list(process_t *p,
                     skip=1;
 
                     /* But if this is in fact a case statement or an elseif statement, then it should be evaluated */
-                    block_type_t type = current_block->type();
+                    block_type_t type = current_block()->type();
                     if (type == SWITCH && args.at(0).completion == L"case" && p->type == INTERNAL_BUILTIN)
                     {
                         skip=0;
                     }
-                    else if (job_get_flag(j, JOB_ELSEIF) && ! job_should_skip_elseif(j, current_block))
+                    else if (job_get_flag(j, JOB_ELSEIF) && ! job_should_skip_elseif(j, current_block()))
                     {
                         skip=0;
                     }
@@ -1357,7 +1372,7 @@ void parser_t::parse_job_argument_list(process_t *p,
                 else
                 {
                     /* If this is an else if, and we should skip it, then don't expand any arguments */
-                    if (job_get_flag(j, JOB_ELSEIF) && job_should_skip_elseif(j, current_block))
+                    if (job_get_flag(j, JOB_ELSEIF) && job_should_skip_elseif(j, current_block()))
                     {
                         skip = 1;
                     }
@@ -1440,7 +1455,7 @@ void parser_t::parse_job_argument_list(process_t *p,
                   Otherwise, bogus errors may be the result. (Do check
                   that token is string, though)
                 */
-                if (current_block->skip && ! unskip)
+                if (current_block()->skip && ! unskip)
                 {
                     tok_next(tok);
                     if (tok_last_type(tok) != TOK_STRING)
@@ -1653,7 +1668,7 @@ int parser_t::parse_job(process_t *p,
     bool unskip = false;    // Maybe we are an elseif inside an if block; if so we may want to evaluate this even if the if block is currently set to skip
     bool allow_bogus_command = false; // If we are an elseif that will not be executed, or an AND or OR that will have been short circuited, don't complain about non-existent commands
 
-    block_t *prev_block = current_block;
+    const block_t *prev_block = current_block();
     scoped_push tokenizer_pos_push(¤t_tokenizer_pos, tok_get_pos(tok));
 
     while (args.empty())
@@ -1806,11 +1821,11 @@ int parser_t::parse_job(process_t *p,
             tok_next(tok);
             while_block_t *wb = NULL;
 
-            if ((current_block->type() != WHILE))
+            if ((current_block()->type() != WHILE))
             {
                 new_block = true;
             }
-            else if ((wb = static_cast(current_block))->status == WHILE_TEST_AGAIN)
+            else if ((wb = static_cast(current_block()))->status == WHILE_TEST_AGAIN)
             {
                 wb->status = WHILE_TEST_FIRST;
             }
@@ -1848,9 +1863,9 @@ int parser_t::parse_job(process_t *p,
             const int else_pos = tok_get_pos(tok);
             /* See if we have any more arguments, that is, whether we're ELSE IF ... or just ELSE. */
             tok_next(tok);
-            if (tok_last_type(tok) == TOK_STRING && current_block->type() == IF)
+            if (tok_last_type(tok) == TOK_STRING && current_block()->type() == IF)
             {
-                const if_block_t *ib = static_cast(current_block);
+                const if_block_t *ib = static_cast(current_block());
 
                 /* If we've already encountered an else, complain */
                 if (ib->else_evaluated)
@@ -1891,7 +1906,7 @@ int parser_t::parse_job(process_t *p,
             continue;
         }
 
-        if (use_function && (unskip || ! current_block->skip))
+        if (use_function && (unskip || ! current_block()->skip))
         {
             bool nxt_forbidden=false;
             wcstring forbid;
@@ -1905,9 +1920,8 @@ int parser_t::parse_job(process_t *p,
               block scopes are pushed on function invocation changes,
               then this check will break.
             */
-            if ((current_block->type() == TOP) &&
-                    (current_block->outer) &&
-                    (current_block->outer->type() == FUNCTION_CALL))
+            const block_t *current = this->block_at_index(0), *parent = this->block_at_index(1);
+            if (current && parent && current->type() == TOP && parent->type() == FUNCTION_CALL)
                 is_function_call = 1;
 
             /*
@@ -1916,7 +1930,7 @@ int parser_t::parse_job(process_t *p,
               may not be called, since that would mean an infinite
               recursion.
             */
-            if (is_function_call && !current_block->had_command)
+            if (is_function_call && !current->had_command)
             {
                 forbid = forbidden_function.empty() ? wcstring(L"") : forbidden_function.back();
                 if (forbid == nxt)
@@ -1963,7 +1977,7 @@ int parser_t::parse_job(process_t *p,
               If we are not executing the current block, allow
               non-existent commands.
             */
-            if (current_block->skip && ! unskip)
+            if (current_block()->skip && ! unskip)
                 allow_bogus_command = true; //note this may already be true for other reasons
 
             if (allow_bogus_command)
@@ -2208,7 +2222,7 @@ int parser_t::parse_job(process_t *p,
 
                 tok_set_pos(tok, (int)end_pos);
 
-                while (prev_block != current_block)
+                while (prev_block != this->current_block())
                 {
                     parser_t::pop_block();
                 }
@@ -2237,7 +2251,7 @@ int parser_t::parse_job(process_t *p,
     {
         if (!is_new_block)
         {
-            current_block->had_command = true;
+            current_block()->had_command = true;
         }
     }
 
@@ -2246,7 +2260,7 @@ int parser_t::parse_job(process_t *p,
         /*
           Make sure the block stack is consistent
         */
-        while (prev_block != current_block)
+        while (prev_block != current_block())
         {
             parser_t::pop_block();
         }
@@ -2280,7 +2294,8 @@ void parser_t::skipped_exec(job_t * j)
             }
             else if (wcscmp(p->argv0(), L"end")==0)
             {
-                if (!current_block->outer->skip)
+                const block_t *parent = this->block_at_index(1);
+                if (parent && ! parent->skip)
                 {
                     exec_job(*this, j);
                     return;
@@ -2289,10 +2304,10 @@ void parser_t::skipped_exec(job_t * j)
             }
             else if (wcscmp(p->argv0(), L"else")==0)
             {
-                if (current_block->type() == IF)
+                if (current_block()->type() == IF)
                 {
                     /* Evaluate this ELSE if the IF expression failed, and so has every ELSEIF (if any) expression thus far */
-                    const if_block_t *ib = static_cast(current_block);
+                    const if_block_t *ib = static_cast(current_block());
                     if (ib->if_expr_evaluated && ! ib->any_branch_taken)
                     {
                         exec_job(*this, j);
@@ -2302,7 +2317,7 @@ void parser_t::skipped_exec(job_t * j)
             }
             else if (wcscmp(p->argv0(), L"case")==0)
             {
-                if (current_block->type() == SWITCH)
+                if (current_block()->type() == SWITCH)
                 {
                     exec_job(*this, j);
                     return;
@@ -2376,7 +2391,7 @@ void parser_t::eval_job(tokenizer_t *tok)
                          || is_event \
                          || (!get_is_interactive()));
 
-            current_block->job = j;
+            current_block()->job = j;
 
             if (get_is_interactive())
             {
@@ -2411,27 +2426,27 @@ void parser_t::eval_job(tokenizer_t *tok)
                 {
                     t2 = get_time();
                     profile_item->cmd = j->command();
-                    profile_item->skipped=current_block->skip;
+                    profile_item->skipped=current_block()->skip;
                 }
 
                 /* If we're an ELSEIF, then we may want to unskip, if we're skipping because of an IF */
                 if (job_get_flag(j, JOB_ELSEIF))
                 {
-                    bool skip_elseif = job_should_skip_elseif(j, current_block);
+                    bool skip_elseif = job_should_skip_elseif(j, current_block());
 
                     /* Record that we're entering an elseif */
                     if (! skip_elseif)
                     {
                         /* We must be an IF block here */
-                        assert(current_block->type() == IF);
-                        static_cast(current_block)->is_elseif_entry = true;
+                        assert(current_block()->type() == IF);
+                        static_cast(current_block())->is_elseif_entry = true;
                     }
 
                     /* Record that in the block too. This is similar to what builtin_else does. */
-                    current_block->skip = skip_elseif;
+                    current_block()->skip = skip_elseif;
                 }
 
-                skip = skip || current_block->skip;
+                skip = skip || current_block()->skip;
                 skip = skip || job_get_flag(j, JOB_WILDCARD_ERROR);
                 skip = skip || job_get_flag(j, JOB_SKIP);
 
@@ -2460,9 +2475,9 @@ void parser_t::eval_job(tokenizer_t *tok)
                     profile_item->exec=(int)(t3-t2);
                 }
 
-                if (current_block->type() == WHILE)
+                if (current_block()->type() == WHILE)
                 {
-                    while_block_t *wb = static_cast(current_block);
+                    while_block_t *wb = static_cast(current_block());
                     switch (wb->status)
                     {
                         case WHILE_TEST_FIRST:
@@ -2476,9 +2491,9 @@ void parser_t::eval_job(tokenizer_t *tok)
                     }
                 }
 
-                if (current_block->type() == IF)
+                if (current_block()->type() == IF)
                 {
-                    if_block_t *ib = static_cast(current_block);
+                    if_block_t *ib = static_cast(current_block());
 
                     if (ib->skip)
                     {
@@ -2491,7 +2506,7 @@ void parser_t::eval_job(tokenizer_t *tok)
                         ib->any_branch_taken = if_result;
 
                         /* Don't execute if the expression failed */
-                        current_block->skip = ! if_result;
+                        current_block()->skip = ! if_result;
                         ib->if_expr_evaluated = true;
                     }
                     else if (ib->is_elseif_entry && ! ib->any_branch_taken)
@@ -2499,7 +2514,7 @@ void parser_t::eval_job(tokenizer_t *tok)
                         /* Maybe mark an ELSEIF branch as taken */
                         bool elseif_taken = (proc_get_last_status() == 0);
                         ib->any_branch_taken = elseif_taken;
-                        current_block->skip = ! elseif_taken;
+                        current_block()->skip = ! elseif_taken;
                         ib->is_elseif_entry = false;
                     }
                 }
@@ -2517,7 +2532,7 @@ void parser_t::eval_job(tokenizer_t *tok)
 
                 proc_set_last_status(1);
             }
-            current_block->job = 0;
+            current_block()->job = 0;
             break;
         }
 
@@ -2579,7 +2594,7 @@ int parser_t::eval(const wcstring &cmdStr, const io_chain_t &io, enum block_type
     const wchar_t * const cmd = cmdStr.c_str();
     size_t forbid_count;
     int code;
-    block_t *start_current_block = current_block;
+    const block_t *start_current_block = current_block();
 
     /* Record the current chain so we can put it back later */
     scoped_push block_io_push(&block_io, io);
@@ -2639,9 +2654,9 @@ int parser_t::eval(const wcstring &cmdStr, const io_chain_t &io, enum block_type
 
     parser_t::pop_block();
 
-    while (start_current_block != current_block)
+    while (start_current_block != current_block())
     {
-        if (current_block == 0)
+        if (current_block() == NULL)
         {
             debug(0,
                   _(L"End of block mismatch. Program terminating."));
@@ -2656,7 +2671,7 @@ int parser_t::eval(const wcstring &cmdStr, const io_chain_t &io, enum block_type
             //debug( 2, L"Status %d\n", proc_get_last_status() );
 
             debug(1,
-                  L"%ls", parser_t::get_block_desc(current_block->type()));
+                  L"%ls", parser_t::get_block_desc(current_block()->type()));
             debug(1,
                   BLOCK_END_ERR_MSG);
             fwprintf(stderr, L"%ls", parser_t::current_line());
@@ -3734,8 +3749,7 @@ block_t::block_t(block_type_t t) :
     src_filename(),
     src_lineno(),
     wants_pop_env(false),
-    event_blocks(),
-    outer(NULL)
+    event_blocks()
 {
 }
 
diff --git a/parser.h b/parser.h
index fa49fcfb7..9b613d3c8 100644
--- a/parser.h
+++ b/parser.h
@@ -137,11 +137,6 @@ public:
     /** List of event blocks. */
     event_blockage_list_t event_blocks;
 
-    /**
-     Next outer block
-    */
-    block_t *outer;
-
     /** Destructor */
     virtual ~block_t();
 };
@@ -301,7 +296,6 @@ class parser_t
 {
 private:
     enum parser_type_t parser_type;
-    std::vector blocks;
 
     /** Whether or not we output errors */
     const bool show_errors;
@@ -332,6 +326,9 @@ private:
 
     /** The jobs associated with this parser */
     job_list_t my_job_list;
+    
+    /** The list of blocks, allocated with new. It's our responsibility to delete these */
+    std::vector block_stack;
 
     /**
        Keeps track of how many recursive eval calls have been made. Eval
@@ -377,9 +374,6 @@ public:
     /** Create a parser of the given type */
     parser_t(enum parser_type_t type, bool show_errors);
 
-    /** The current innermost block, allocated with new */
-    block_t *current_block;
-
     /** Global event blocks */
     event_blockage_list_t global_event_blocks;
 
@@ -441,6 +435,20 @@ public:
 
     /** Set the current position in the latest string of the tokenizer. */
     void set_pos(int p);
+    
+    /** Returns the block at the given index. 0 corresponds to the innermost block. Returns NULL when idx is at or equal to the number of blocks. */
+    const block_t *block_at_index(size_t idx) const;
+    block_t *block_at_index(size_t idx);
+    
+    /** Returns the current (innermost) block */
+    const block_t *current_block() const;
+    block_t *current_block();
+    
+    /** Count of blocks */
+    size_t block_count() const
+    {
+        return block_stack.size();
+    }
 
     /** Get the string currently parsed */
     const wchar_t *get_buffer() const;
@@ -533,7 +541,7 @@ public:
     /**
        Write a stack trace starting at the specified block to the specified wcstring
     */
-    void stack_trace(block_t *b, wcstring &buff);
+    void stack_trace(size_t block_idx, wcstring &buff);
 
     int get_block_type(const wchar_t *cmd) const;
     const wchar_t *get_block_command(int type) const;
diff --git a/reader.cpp b/reader.cpp
index 5660ff268..b0cbd8a35 100644
--- a/reader.cpp
+++ b/reader.cpp
@@ -2823,14 +2823,11 @@ static void handle_end_loop()
     job_t *j;
     int stopped_jobs_count=0;
     int is_breakpoint=0;
-    block_t *b;
-    parser_t &parser = parser_t::principal_parser();
+    const parser_t &parser = parser_t::principal_parser();
 
-    for (b = parser.current_block;
-            b;
-            b = b->outer)
+    for (size_t i = 0; i < parser.block_count(); i++)
     {
-        if (b->type() == BREAKPOINT)
+        if (parser.block_at_index(i)->type() == BREAKPOINT)
         {
             is_breakpoint = 1;
             break;