Index: commands/pm/pm.drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/pm/pm.drush.inc,v
retrieving revision 1.36
diff -u -r1.36 pm.drush.inc
--- commands/pm/pm.drush.inc	21 May 2009 06:04:42 -0000	1.36
+++ commands/pm/pm.drush.inc	26 May 2009 16:35:33 -0000
@@ -290,7 +290,7 @@
     $info = $form['validation_modules']['#value'][$module]->info;
     $rows[] = array($info['name'] . ' (' . $module . ')', $enabled, truncate_utf8($info['description'], 60, FALSE, TRUE));
   }
-  drush_print_table($rows, 2, TRUE);
+  drush_print_table($rows, TRUE);
   
   // Space delimited list for use by other scripts. Set the --pipe option.
   drush_print_pipe(implode(' ', $pipe));
@@ -416,7 +416,7 @@
     return drush_set_error('DRUSH_PM_PROJECT_NOT_FOUND', dt('No information available.'));
   }
   else {
-    return drush_print_table($rows, FALSE, TRUE);
+    return drush_print_table($rows, TRUE);
   }
 }
 
Index: commands/pm/updatecode.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/pm/updatecode.inc,v
retrieving revision 1.10
diff -u -r1.10 updatecode.inc
--- commands/pm/updatecode.inc	20 May 2009 04:28:18 -0000	1.10
+++ commands/pm/updatecode.inc	26 May 2009 16:35:33 -0000
@@ -63,7 +63,7 @@
   drush_print(dt('Update information last refreshed: ') . ($last  ? format_date($last) : dt('Never')));
   drush_print();
   drush_print(dt("Update status information on all installed and enabled Drupal modules:"));
-  drush_print_table($rows, 2, TRUE);
+  drush_print_table($rows, TRUE);
   drush_print();
 
   // If specific project updates were requested then remove releases for all others
Index: includes/drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/includes/drush.inc,v
retrieving revision 1.39
diff -u -r1.39 drush.inc
--- includes/drush.inc	20 May 2009 20:58:37 -0000	1.39
+++ includes/drush.inc	26 May 2009 16:35:33 -0000
@@ -345,7 +345,7 @@
                 // '[command] is a token representing the current command. @see pm_drush_engine_version_control().
                 $rows[] = array(str_replace('[command]', $commandstring, $name), dt($description));
               }
-              drush_print_table($rows, 2);
+              drush_print_table($rows, false, array(40));
               unset($rows);
               drush_print();
             }
@@ -484,66 +484,122 @@
 
 /**
  * Print a formatted table.
+ * 
  * @param $rows
- *   The rows to print
- * @param $indent
- *   Indentation for the whole table
+ *   The rows to print.
  * @param $header
- *   If TRUE, the first line will be treated as table
- *   header and therefore be underlined.
- */
-function drush_print_table($rows, $indent = 0, $header = FALSE) {
-  if (count($rows) == 0) {
-    // Nothing to output.
-    return;
-  }
-
-  $indent = str_repeat(' ', $indent);
-  $format = _drush_get_table_row_format($rows);
-
-  $header_printed = FALSE;
-  foreach ($rows as $cols) {
-    // Print the current line.
-    print $indent . vsprintf($format, $cols) . "\n";
-    // Underline the first row if $header is set to true.
-    if (!$header_printed && $header) {
-      $headers = array();
-      foreach ($cols as $col) {
-        $headers[] = str_repeat('-', strlen($col));
+ *   If TRUE, the first line will be treated as table header and therefore be
+ *   underlined.
+ * @param $widths
+ *   The widths of each column (in characters) to use - if not specified this
+ *   will be determined automatically, based on a "best fit" algorithm.
+ */
+function drush_print_table($rows, $header = FALSE, $widths = array()) {
+  $tbl = new Console_Table(CONSOLE_TABLE_ALIGN_LEFT , '');
+
+  $auto_widths = drush_table_column_autowidth($rows, $widths);
+
+  // Do wordwrap on all cells.
+  $newrows = array();
+  foreach ($rows as $rowkey => $row) {
+    foreach ($row as $col_num => $cell) {
+      $newrows[$rowkey][$col_num] = wordwrap($cell, $auto_widths[$col_num], "\n", TRUE);
+      if (isset($widths[$col_num])) {
+        $newrows[$rowkey][$col_num] = str_pad($newrows[$rowkey][$col_num], $widths[$col_num]);
       }
-      print $indent . trim(vsprintf($format, $headers)) . "\n";
-      $header_printed = TRUE;
     }
   }
+  if ($header) {
+    $headers = array_shift($newrows);
+    $tbl->setHeaders($headers);
+  }
+
+  $tbl->addData($newrows);
+  print $tbl->getTable();
 }
 
 /**
- * Create the table row format string to be used in vsprintf().
+ * Determine the best fit for column widths.
+ * 
+ * @param $rows
+ *   The rows to use for calculations.
+ * @param $widths
+ *   Manually specified widths of each column (in characters) - these will be
+ *   left as is.
  */
-function _drush_get_table_row_format($table) {
-  $widths = _drush_get_table_column_widths($table);
-  foreach ($widths as $col_width) {
-    $col_formats[] = "%-{$col_width}s";
+function drush_table_column_autowidth($rows, $widths) {
+  $auto_widths = $widths;
+  
+  // First we determine the distribution of row lengths in each column.
+  // This is an array of descending character length keys (i.e. starting at
+  // the rightmost character column), with the value indicating the number
+  // of rows where that character column is present.
+  $col_dist = array();
+  foreach ($rows as $rowkey => $row) {
+    foreach ($row as $col_num => $cell) {
+      if (empty($widths[$col_num])) {
+        $length = strlen($cell);
+        while ($length > 0) {
+          if (!isset($col_dist[$col_num][$length])) {
+            $col_dist[$col_num][$length] = 0;
+          }
+          $col_dist[$col_num][$length]++;
+          $length--;
+        }
+      }
+    }
+  }
+  foreach ($col_dist as $col_num => $count) {
+    // Sort the distribution in decending key order.
+    krsort($col_dist[$col_num]);
+    // Initially we set all columns to their "ideal" longest width
+    // - i.e. the width of their longest column.
+    $auto_widths[$col_num] = max(array_keys($col_dist[$col_num]));
   }
-  $format = implode("\t", $col_formats);
-  return $format;
-}
 
-/**
- * Calculate table column widths.
- */
-function _drush_get_table_column_widths($table) {
-  $widths = array();
-  foreach ($table as $row => $cols) {
-    foreach ($cols as $col => $value) {
-      $old_width = isset($widths[$col]) ? $widths[$col] : 0;
-      $widths[$col] = max($old_width, strlen((string)$value));
+  // We determine what width we have available to use, and what width the
+  // above "ideal" columns take up.
+  $available_width = drush_get_context('DRUSH_COLUMNS', 80) - (count($auto_widths) * 2);
+  $auto_width_current = array_sum($auto_widths);
+  
+  // If we need to reduce a column so that we can fit the space we use this
+  // loop to figure out which column will cause the "least wrapping",
+  // (relative to the other columns) and reduce the width of that column.
+  while ($auto_width_current > $available_width) {
+    $count = 0;
+    $width = 0;
+    foreach ($col_dist as $col_num => $counts) {
+      // If we are just starting out, select the first column.
+      if ($count == 0 ||
+         // OR: if this column would cause less wrapping than the currently
+         // selected column, then select it.
+         (current($counts) < $count) ||
+         // OR: if this column would cause the same amount of wrapping, but is
+         // longer, then we choose to wrap the longer column (proportionally
+         // less wrapping, and helps avoid triple line wraps).
+         (current($counts) == $count && key($counts) > $width)) {
+        // Select the column number, and record the count and current width
+        // for later comparisons.
+        $column = $col_num;
+        $count = current($counts);
+        $width = key($counts);
+      }
+    }
+    if ($width <= 1) {
+      // If we have reached a width of 1 then give up, so wordwrap can still progress.
+      break;
     }
+    // Reduce the width of the selected column.
+    $auto_widths[$column]--;
+    // Reduce our overall table width counter.
+    $auto_width_current--;
+    // Remove the corresponding data from the disctribution, so next time
+    // around we use the data for the row to the left.
+    unset($col_dist[$column][$width]);
   }
-  return $widths;
+  return $auto_widths;
 }
 
-
 /**
  * @defgroup logging Logging information to be provided as output.
  * @{
Index: includes/environment.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/includes/environment.inc,v
retrieving revision 1.32
diff -u -r1.32 environment.inc
--- includes/environment.inc	21 May 2009 05:54:45 -0000	1.32
+++ includes/environment.inc	26 May 2009 16:35:33 -0000
@@ -107,6 +107,16 @@
 define('DRUSH_MINIMUM_PHP', '5.2.0');
 
 /**
+ * Supported version of Console Table. This is displayed in the manual install help.
+ */
+define('DRUSH_TABLE_VERSION', '1.1.3');
+
+/**
+ * URL for automatic file download for supported version of Console Table.
+ */
+define('DRUSH_TABLE_URL', 'http://cvs.php.net/viewvc.cgi/pear/Console_Table/Table.php?revision=1.28&view=co');
+
+/**
  * Helper function listing phases.
  *
  * For commands that need to iterate through the phases, such as help
@@ -299,6 +309,23 @@
     return drush_bootstrap_error('DRUSH_SAFE_MODE', dt('PHP safe mode is activated. Drush requires that safe mode is disabled.'));
   }
 
+  // Attempt to download Console Table, via various methods.
+  if (!file_exists(DRUSH_BASE_PATH . '/includes/table.inc')) {
+    if ($file = @file_get_contents(DRUSH_TABLE_URL)) {
+      @file_put_contents(DRUSH_BASE_PATH . '/includes/table.inc', $file);
+    }
+    if (!file_exists(DRUSH_BASE_PATH . '/includes/table.inc')) {
+      drush_shell_exec("wget -q -O includes/table.inc " . DRUSH_TABLE_URL);
+      if (!file_exists(DRUSH_BASE_PATH . '/includes/table.inc')) {
+        drush_shell_exec("curl -s -o includes/table.inc " . DRUSH_TABLE_URL);
+        if (!file_exists(DRUSH_BASE_PATH . '/includes/table.inc')) {
+          return drush_bootstrap_error('DRUSH_TABLES_INC', dt('Drush needs a copy of the PEAR Console_Table library saved as Drush includes/table.inc. Drush attempted to download this automatically, but failed. To continue you will need to download the !version package from http://pear.php.net/package/Console_Table, extract, and move the file Table.php to includes/table.inc.', array('!version' => DRUSH_TABLE_VERSION)));
+        }
+      }
+    }
+  }
+  require_once DRUSH_BASE_PATH . '/includes/table.inc';
+
   return TRUE;
 }
 
Index: commands/core/drupal/update_5.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/core/drupal/update_5.inc,v
retrieving revision 1.4
diff -u -r1.4 update_5.inc
--- commands/core/drupal/update_5.inc	15 May 2009 19:02:20 -0000	1.4
+++ commands/core/drupal/update_5.inc	26 May 2009 16:35:33 -0000
@@ -66,7 +66,7 @@
         drush_print(dt('The following updates are pending:'));
         drush_print();
         array_unshift($pending, array($module . ' module'));
-        drush_print_table($pending, 0, TRUE);
+        drush_print_table($pending, TRUE);
         drush_print();
         if (!drush_confirm(dt('Do you wish to run all pending updates?'))) {
           drush_die('Aborting.');
Index: commands/core/drupal/update_6.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/core/drupal/update_6.inc,v
retrieving revision 1.6
diff -u -r1.6 update_6.inc
--- commands/core/drupal/update_6.inc	20 May 2009 21:12:37 -0000	1.6
+++ commands/core/drupal/update_6.inc	26 May 2009 16:35:33 -0000
@@ -377,7 +377,7 @@
     drush_print(dt('The following updates are pending:'));
     drush_print();
     array_unshift($pending, array($module . ' module'));
-    drush_print_table($pending, 0, TRUE);
+    drush_print_table($pending, TRUE);
     drush_print();
     if (!drush_confirm(dt('Do you wish to run all pending updates?'))) {
       drush_die('Aborting.');
Index: commands/core/drupal/update_7.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/core/drupal/update_7.inc,v
retrieving revision 1.6
diff -u -r1.6 update_7.inc
--- commands/core/drupal/update_7.inc	21 May 2009 01:20:07 -0000	1.6
+++ commands/core/drupal/update_7.inc	26 May 2009 16:35:33 -0000
@@ -514,7 +514,7 @@
     drush_print(dt('The following updates are pending:'));
     drush_print();
     array_unshift($pending, array($module . ' module'));
-    drush_print_table($pending, 0, TRUE);
+    drush_print_table($pending, TRUE);
     drush_print();
     if (!drush_confirm(dt('Do you wish to run all pending updates?'))) {
       drush_die('Aborting.');
Index: commands/core/core.drush.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drush/commands/core/core.drush.inc,v
retrieving revision 1.27
diff -u -r1.27 core.drush.inc
--- commands/core/core.drush.inc	8 May 2009 03:46:15 -0000	1.27
+++ commands/core/core.drush.inc	26 May 2009 16:35:33 -0000
@@ -154,11 +154,11 @@
         $rows = array();
         foreach($commands as $key => $command) {
           if (!array_key_exists($key, $printed_rows)) {
-            $rows[$key] = array(sprintf("%-20s", $key), $commands[$key]['description']);
+            $rows[$key] = array($key, $commands[$key]['description']);
             $pipe[] = "\"$key\"";
           }
         }
-        drush_print_table($rows, 2);
+        drush_print_table($rows, FALSE, array(0 => 20));
         $printed_rows = array_merge($printed_rows, $rows);
       }
       else {
@@ -397,7 +397,7 @@
     drush_log(dt('Last !count watchdog log messages:', array('!count' => $limit)));
 
     array_unshift($rows, array(dt('Date'), dt('Severity'), dt('Type'), dt('Message'), dt('User')));
-    drush_print_table($rows, 2, TRUE);
+    drush_print_table($rows, TRUE);
   }
 }
 
