Index: geshifilter.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geshifilter/geshifilter.admin.inc,v
retrieving revision 1.20
diff -u -b -u -p -r1.20 geshifilter.admin.inc
--- geshifilter.admin.inc	27 Jun 2009 12:54:15 -0000	1.20
+++ geshifilter.admin.inc	30 Jun 2009 00:21:14 -0000
@@ -23,6 +23,7 @@ function _geshifilter_filter_settings($f
   if (geshifilter_use_format_specific_options()) {
     // tags and attributes
     $form['geshifilter']['general_tags'] = _geshifilter_general_highlight_tags_settings($format);
+    $form['#validate'][] = '_geshifilter_tag_styles_validate';
     // per language tags
     $form['geshifilter']['per_language_settings'] = array(
       '#type' => 'fieldset',
@@ -41,6 +42,22 @@ function _geshifilter_filter_settings($f
 }
 
 /**
+ * Validation handler for the tag styles form element.
+ * Covers usage in the general form of geshifilter_admin_general_settings()
+ * and the format specific (sub)form of _geshifilter_filter_settings().
+ */
+function _geshifilter_tag_styles_validate($form, &$form_state) {
+  // If we're coming from the _geshifilter_filter_settings (sub)form, we should
+  // take the input format into account.
+  $f = isset($form_state['values']['format']) ? '_'. $form_state['values']['format'] : '';
+
+  // Check that at least one tag style is selected.
+  if (0 == count(array_filter($form_state['values']["geshifilter_tag_styles{$f}"]))) {
+    form_set_error("geshifilter_tag_styles{$f}", t('At least one tag style should be selected.'));
+  }
+}
+
+/**
  * General settings form for the GeSHi filter.
  */
 function geshifilter_admin_general_settings(&$form_state) {
@@ -100,9 +117,10 @@ function geshifilter_admin_general_setti
       '#default_value' => geshifilter_use_format_specific_options(),
       '#description' => t('Enable seperate tag settings of the GeSHi filter for each <a href="!input_formats">input format</a> instead of global tag settings.', array('!input_formats' => url('admin/settings/filters'))),
     );
-    // generic tags
+    // Generic tags settings.
     if (!geshifilter_use_format_specific_options()) {
       $form['geshifilter_tag_options']['geshifilter_general_tags'] = _geshifilter_general_highlight_tags_settings();
+      $form['#validate'][] = '_geshifilter_tag_styles_validate';
     }
 
     // GeSHi filter highlighting options
@@ -358,19 +376,20 @@ function _geshifilter_general_highlight_
     '#default_value' => geshifilter_tags($format),
     '#description' => t('Tags that should activate the GeSHi syntax highlighting. Specify a space-separated list of tagnames.'),
   );
-  // tag style
-  $form["geshifilter_brackets$f"] = array(
-    '#type' => 'select',
-    '#title' => t('Tag style'),
+  // Container tag styles.
+  $form["geshifilter_tag_styles$f"] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Container tag style'),
     '#options' => array(
-      GESHIFILTER_BRACKETS_ANGLE => '<foo>',
-      GESHIFILTER_BRACKETS_SQUARE => '[foo]',
-      GESHIFILTER_BRACKETS_BOTH => t('!angle or !square', array('!angle' => '<foo>', '!square' => '[foo]')),
+      GESHIFILTER_BRACKETS_ANGLE => '<code>'. check_plain('<foo> ... </foo>') .'</code>',
+      GESHIFILTER_BRACKETS_SQUARE => '<code>'. check_plain('[foo] ... [/foo]') .'</code>',
+      GESHIFILTER_BRACKETS_DOUBLESQUARE => '<code>'. check_plain('[[foo]] ... [[/foo]]') .'</code>',
     ),
-    '#default_value' => _geshifilter_brackets($format),
-    '#description' => t('Select which brackets should be used for the source code container tags.'),
+    '#default_value' => _geshifilter_tag_styles($format),
+    '#description' => t('Select the container tag styles that should trigger GeSHi syntax highlighting.'),
   );
-  // PHP specific delimiters
+  // PHP specific delimiters.
+  // @todo: merge this option into geshifilter_tag_styles$f.
   $form['geshifilter']["geshifilter_enable_php_delimiters$f"] = array(
     '#type' => 'checkbox',
     '#title' => t('Also apply syntax highlighting to &lt;?php ... ?&gt; style PHP source code blocks.'),
Index: geshifilter.conflicts.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geshifilter/geshifilter.conflicts.inc,v
retrieving revision 1.4
diff -u -b -u -p -r1.4 geshifilter.conflicts.inc
--- geshifilter.conflicts.inc	21 Jul 2008 17:44:23 -0000	1.4
+++ geshifilter.conflicts.inc	30 Jun 2009 00:21:15 -0000
@@ -90,11 +90,11 @@ function _geshifilter_htmlfilter_conflic
 }
 
 /**
- * conflict detection for codefilter
+ * Conflict detection for codefilter.
  */
 function _geshifilter_codefilter_conflicts($format, $cfilter, $geshifilter) {
   $conflicts = array();
-  if (_geshifilter_brackets($format) != GESHIFILTER_BRACKETS_SQUARE) {
+  if (in_array(GESHIFILTER_BRACKETS_ANGLE, array_filter(_geshifilter_tag_styles($format)))) {
     list($generic_code_tags, $language_tags, $tag_to_lang) = _geshifilter_get_tags($format);
     if (in_array('code', $generic_code_tags) || in_array('code', $language_tags)) {
       $conflicts[] = array(
Index: geshifilter.filtertips.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geshifilter/geshifilter.filtertips.inc,v
retrieving revision 1.5
diff -u -b -u -p -r1.5 geshifilter.filtertips.inc
--- geshifilter.filtertips.inc	21 Jul 2008 17:44:23 -0000	1.5
+++ geshifilter.filtertips.inc	30 Jun 2009 00:21:15 -0000
@@ -12,12 +12,34 @@ require_once drupal_get_path('module', '
  * Implementation for geshifilter_filter_tips()
  */
 function _geshifilter_filter_tips($delta, $format, $long = FALSE) {
-  if (_geshifilter_brackets($format) == GESHIFILTER_BRACKETS_SQUARE) {
-    $bracket_open = '[';
-    $bracket_close = ']';
+
+  // Get the supported tag styles.
+  $tag_styles = array_filter(_geshifilter_tag_styles($format));
+  $tag_style_examples = array();
+  $bracket_open = NULL;
+  if (in_array(GESHIFILTER_BRACKETS_ANGLE, $tag_styles)) {
+    if (!$bracket_open) {
+      $bracket_open = check_plain('<');
+      $bracket_close = check_plain('>');
+    }
+    $tag_style_examples[] = '<code>'. check_plain('<foo>') .'</code>';
+  }
+  if (in_array(GESHIFILTER_BRACKETS_SQUARE, $tag_styles)) {
+    if (!$bracket_open) {
+      $bracket_open = check_plain('[');
+      $bracket_close = check_plain(']');
+    }
+    $tag_style_examples[] = '<code>'. check_plain('[foo]') .'</code>';
+  }
+  if (in_array(GESHIFILTER_BRACKETS_DOUBLESQUARE, $tag_styles)) {
+    if (!$bracket_open) {
+      $bracket_open = check_plain('[[');
+      $bracket_close = check_plain(']]');
   }
-  else {
-    // default brackets
+    $tag_style_examples[] = '<code>'. check_plain('[[foo]]') .'</code>';
+  }
+  if (!$bracket_open) {
+    drupal_set_message(t('Could not determine a valid tag style for GeSHi filtering.'), 'error');
     $bracket_open = '&lt;';
     $bracket_close = '&gt;';
   }
@@ -70,15 +92,18 @@ function _geshifilter_filter_tips($delta
     }
     $items[] = t('The language for the generic syntax highlighting tags can be specified with one of the attribute(s): %attributes. The possible values are: !languages.', array('%attributes' => implode(', ', $lang_attributes), '!languages' => implode(', ', $att_for_full)));
 
+    // Tag style options.
+    if (count($tag_style_examples) > 1) {
+      $items[] = t('The supported tag styles are: !tag_styles.' , array('!tag_styles' => implode(', ', $tag_style_examples)));
+    }
+
     // line numbering options
     $items[] = t('<em>Line numbering</em> can be enabled/disabled with the attribute "%linenumbers". Possible values are: "%off" for no line numbers, "%normal" for normal line numbers and "%fancy" for fancy line numbers (every n<sup>th</sup> line number highlighted). The start line number can be specified with the attribute "%start", which implicitly enables normal line numbering. For fancy line numbering the interval for the highlighted line numbers can be specified with the attribute "%fancy", which implicitly enables fancy line numbering.', array('%linenumbers' => GESHIFILTER_ATTRIBUTE_LINE_NUMBERING, '%off' => 'off', '%normal' => 'normal', '%fancy' => 'fancy', '%start' => GESHIFILTER_ATTRIBUTE_LINE_NUMBERING_START, '%fancy' => GESHIFILTER_ATTRIBUTE_FANCY_N));
 
     // block versus inline
     $items[] = t('If the source code between the tags contains a newline (e.g. immediatly after the opening tag), the highlighted source code will be displayed as a code block. Otherwise it will be displayed inline.');
 
-    if (_geshifilter_brackets($format) == GESHIFILTER_BRACKETS_BOTH) {
-      $items[] = t('Beside the tag style "!angle" it is also possible to use "!bracket".' , array('!angle' => '<code>&lt;foo&gt;</code>', '!bracket' => '<code>[foo]</code>'));
-    }
+
     $output .= theme('item_list', $items);
 
     // Defaults
@@ -163,8 +188,9 @@ function _geshifilter_filter_tips($delta
       $tags[] = '<code>'. $bracket_open . $tag . $bracket_close .'</code>';
     }
     $output = t('You can enable syntax highlighting of source code with the following tags: !tags.', array('!tags' => implode(', ', $tags)));
-    if (_geshifilter_brackets($format) == GESHIFILTER_BRACKETS_BOTH) {
-      $output .= ' '. t('Beside the tag style "!angle" it is also possible to use "!bracket".' , array('!angle' => '<code>&lt;foo&gt;</code>', '!bracket' => '<code>[foo]</code>'));
+    // Tag style options.
+    if (count($tag_style_examples) > 1) {
+      $output .= ' '. t('The supported tag styles are: !tag_styles.' , array('!tag_styles' => implode(', ', $tag_style_examples)));
     }
     if (_geshifilter_php_delimeters($format)) {
       $output .= ' '. t('PHP source code can also be enclosed in &lt;?php ... ?&gt; or &lt;% ... %&gt;.');
Index: geshifilter.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geshifilter/geshifilter.inc,v
retrieving revision 1.5
diff -u -b -u -p -r1.5 geshifilter.inc
--- geshifilter.inc	21 Jul 2008 17:44:23 -0000	1.5
+++ geshifilter.inc	30 Jun 2009 00:21:15 -0000
@@ -179,11 +179,14 @@ function _geshifilter_php_delimeters($fo
   return variable_get("geshifilter_enable_php_delimiters_{$format}", _geshifilter_php_delimeters());
 }
 
-function _geshifilter_brackets($format = NULL) {
+function _geshifilter_tag_styles($format = NULL) {
   if (!geshifilter_use_format_specific_options() || $format === NULL) {
-    return variable_get('geshifilter_brackets', GESHIFILTER_BRACKETS_BOTH);
+    return variable_get('geshifilter_tag_styles', array(
+      GESHIFILTER_BRACKETS_ANGLE => GESHIFILTER_BRACKETS_ANGLE,
+      GESHIFILTER_BRACKETS_SQUARE => GESHIFILTER_BRACKETS_SQUARE,
+    ));
   }
-  return variable_get("geshifilter_brackets_{$format}", _geshifilter_brackets());
+  return variable_get("geshifilter_tag_styles_{$format}", _geshifilter_tag_styles());
 }
 
 function geshifilter_language_tags($language, $format = NULL) {
Index: geshifilter.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geshifilter/geshifilter.install,v
retrieving revision 1.7
diff -u -b -u -p -r1.7 geshifilter.install
--- geshifilter.install	4 Jan 2009 17:17:47 -0000	1.7
+++ geshifilter.install	30 Jun 2009 00:21:15 -0000
@@ -32,10 +32,35 @@ function geshifilter_uninstall() {
 }
 
 /**
- * Implementation of hook_update_N()
+ * Implementation of hook_update_N().
  */
 function geshifilter_update_1() {
   // clear the cache of available languages
   variable_del('geshifilter_available_languages');
   return array();
 }
+
+/**
+ * Implementation of hook_update_N().
+ *
+ * Upgrade path from usage of geshifilter_brackets variable
+ * to geshifilter_tag_styles variable.
+ */
+function geshifilter_update_601() {
+  $geshifilter_brackets = variable_get('geshifilter_brackets', NULL);
+  switch ($geshifilter_brackets) {
+    case GESHIFILTER_BRACKETS_ANGLE:
+    case GESHIFILTER_BRACKETS_SQUARE:
+      variable_set('geshifilter_tag_styles', array($geshifilter_brackets => $geshifilter_brackets));
+      break;
+    case GESHIFILTER_BRACKETS_BOTH:
+      variable_set('geshifilter_tag_styles', array(
+        GESHIFILTER_BRACKETS_ANGLE => GESHIFILTER_BRACKETS_ANGLE,
+        GESHIFILTER_BRACKETS_SQUARE => GESHIFILTER_BRACKETS_SQUARE,
+      ));
+      break;
+  }
+  variable_del('geshifilter_brackets');
+  return array();
+}
+
Index: geshifilter.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geshifilter/geshifilter.module,v
retrieving revision 1.45
diff -u -b -u -p -r1.45 geshifilter.module
--- geshifilter.module	27 Jun 2009 12:54:15 -0000	1.45
+++ geshifilter.module	30 Jun 2009 00:21:15 -0000
@@ -24,7 +24,8 @@ define('GESHIFILTER_ATTRIBUTE_FANCY_N', 
 
 define('GESHIFILTER_BRACKETS_ANGLE', 1);
 define('GESHIFILTER_BRACKETS_SQUARE', 2);
-define('GESHIFILTER_BRACKETS_BOTH', 3);
+define('GESHIFILTER_BRACKETS_BOTH', 3); //@todo: remove this constant when not needed/used anymore.
+define('GESHIFILTER_BRACKETS_DOUBLESQUARE', 4);
 
 define('GESHIFILTER_LINE_NUMBERS_DEFAULT_NONE', 0);
 define('GESHIFILTER_LINE_NUMBERS_DEFAULT_NORMAL', 1);
Index: geshifilter.pages.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geshifilter/geshifilter.pages.inc,v
retrieving revision 1.10
diff -u -b -u -p -r1.10 geshifilter.pages.inc
--- geshifilter.pages.inc	4 Jan 2009 17:44:38 -0000	1.10
+++ geshifilter.pages.inc	30 Jun 2009 00:21:15 -0000
@@ -107,22 +107,25 @@ function _geshifilter_prepare($format, $
   // Also matches "<code>...$"  where "$" refers to end of string, not end of
   // line (because PCRE_MULTILINE (modifier 'm') is not enabled), so matching
   // still works when teaser view trims inside the source code.
-  switch (_geshifilter_brackets($format)) {
-    case GESHIFILTER_BRACKETS_ANGLE:
+
+  // Replace the code container tag brackets
+  // and prepare the container content (newline and angle bracket protection).
+  // @todo: make sure that these replacements can be done in serie.
+  $tag_styles = array_filter(_geshifilter_tag_styles($format));
+  if (in_array(GESHIFILTER_BRACKETS_ANGLE, $tag_styles)) {
       $pattern = '#(<)('. $tags_string .')((\s+[^>]*)*)(>)(.*?)(</\2\s*>|$)#s';
-      break;
-    case GESHIFILTER_BRACKETS_SQUARE:
-      $pattern = '#(\[)('. $tags_string .')((\s+[^\]]*)*)(\])(.*?)(\[/\2\s*\]|$)#s';
-      break;
-    case GESHIFILTER_BRACKETS_BOTH:
-      $pattern = '#([<\[])('. $tags_string .')((\s+[^>\]]*)*)([>\]])(.*?)(\1/\2\s*\5|$)#s';
-      break;
+    $text = preg_replace_callback($pattern, create_function('$match', "return _geshifilter_prepare_callback(\$match, $format);"), $text);
   }
-  // replace the code container tag brackets
-  // and prepare the container content (newline and angle bracket protection)
+  if (in_array(GESHIFILTER_BRACKETS_SQUARE, $tag_styles)) {
+    $pattern = '#((?<!\[)\[)('. $tags_string .')((\s+[^\]]*)*)(\](?!\[))(.*?)((?<!\[)\[/\2\s*\](?<!\[)|$)#s';
   $text = preg_replace_callback($pattern, create_function('$match', "return _geshifilter_prepare_callback(\$match, $format);"), $text);
+  }
+  if (in_array(GESHIFILTER_BRACKETS_DOUBLESQUARE, $tag_styles)) {
+    $pattern = '#(\[\[)('. $tags_string .')((\s+[^\]]*)*)(\]\])(.*?)(\[\[/\2\s*\]\]|$)#s';
+    $text = preg_replace_callback($pattern, create_function('$match', "return _geshifilter_prepare_callback(\$match, $format);"), $text);
+  }
+  // Prepare < ?php ... ? > blocks.
   if (_geshifilter_php_delimeters($format)) {
-    // prepare < ?php ... ? > blocks
     $text = preg_replace_callback('#[\[<](\?php|\?PHP|%)(.+?)((\?|%)[\]>]|$)#s', '_geshifilter_prepare_php_callback', $text);
   }
   return $text;
Index: tests/geshifilter.admin.test
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geshifilter/tests/geshifilter.admin.test,v
retrieving revision 1.1
diff -u -b -u -p -r1.1 geshifilter.admin.test
--- tests/geshifilter.admin.test	28 Apr 2008 22:52:17 -0000	1.1
+++ tests/geshifilter.admin.test	30 Jun 2009 00:21:15 -0000
@@ -59,7 +59,10 @@ class GeshiFilterAdministrationTest exte
 
     // set some default GeSHi filter admin settings
     $this->drupalVariableSet('geshifilter_format_specific_options', FALSE);
-    $this->drupalVariableSet('geshifilter_brackets', GESHIFILTER_BRACKETS_BOTH);
+    $this->drupalVariableSet('geshifilter_tag_styles', array(
+      GESHIFILTER_BRACKETS_ANGLE => GESHIFILTER_BRACKETS_ANGLE,
+      GESHIFILTER_BRACKETS_SQUARE => GESHIFILTER_BRACKETS_SQUARE,
+    ));
     $this->drupalVariableSet('geshifilter_default_line_numbering', GESHIFILTER_LINE_NUMBERS_DEFAULT_NONE);
 
   }
Index: tests/geshifilter.pages.test
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geshifilter/tests/geshifilter.pages.test,v
retrieving revision 1.3
diff -u -b -u -p -r1.3 geshifilter.pages.test
--- tests/geshifilter.pages.test	1 May 2008 16:57:55 -0000	1.3
+++ tests/geshifilter.pages.test	30 Jun 2009 00:21:15 -0000
@@ -74,7 +74,10 @@ class GeshiFilterTest extends DrupalTest
         // Set default highlighting mode to "do nothing".
     $this->drupalVariableSet('geshifilter_default_highlighting', GESHIFILTER_DEFAULT_PLAINTEXT);
     $this->drupalVariableSet('geshifilter_format_specific_options', FALSE);
-    $this->drupalVariableSet('geshifilter_brackets', GESHIFILTER_BRACKETS_BOTH);
+    $this->drupalVariableSet('geshifilter_tag_styles', array(
+      GESHIFILTER_BRACKETS_ANGLE => GESHIFILTER_BRACKETS_ANGLE,
+      GESHIFILTER_BRACKETS_SQUARE => GESHIFILTER_BRACKETS_SQUARE,
+    ));
     $this->drupalVariableSet('geshifilter_default_line_numbering', GESHIFILTER_LINE_NUMBERS_DEFAULT_NONE);
 
     // log out as filter admin
@@ -197,15 +200,20 @@ class GeshiFilterTest extends DrupalTest
     // body material
     $source_code = "//C++ source code\nfor (int i=0; i<10; ++i) {\n  fun(i);\n  bar.foo(x, y);\n server->start(&pool); \n}";
 
-    $this->drupalVariableSet('geshifilter_brackets', GESHIFILTER_BRACKETS_BOTH);
+    $this->drupalVariableSet('geshifilter_tag_styles', array(
+      GESHIFILTER_BRACKETS_ANGLE => GESHIFILTER_BRACKETS_ANGLE,
+      GESHIFILTER_BRACKETS_SQUARE => GESHIFILTER_BRACKETS_SQUARE,
+    ));
     $this->assertGeshiFilterHighlighting('<code language="cpp">'. $source_code .'</code>',
       array(array($source_code, 'cpp', 0, 1, FALSE)),
-      t('Checking <foo> brackets style in GESHIFILTER_BRACKETS_BOTH mode'));
+      t('Checking <foo> brackets style in angle+square tag style mode'));
     $this->assertGeshiFilterHighlighting('[code language="cpp"]'. $source_code .'[/code]',
       array(array($source_code, 'cpp', 0, 1, FALSE)),
-      t('Checking [foo] brackets style in GESHIFILTER_BRACKETS_BOTH mode'));
+      t('Checking [foo] brackets style in angle+square tag style mode mode'));
 
-    $this->drupalVariableSet('geshifilter_brackets', GESHIFILTER_BRACKETS_ANGLE);
+    $this->drupalVariableSet('geshifilter_tag_styles', array(
+      GESHIFILTER_BRACKETS_ANGLE => GESHIFILTER_BRACKETS_ANGLE,
+    ));
     $this->assertGeshiFilterHighlighting('<code language="cpp">'. $source_code .'</code>',
       array(array($source_code, 'cpp', 0, 1, FALSE)),
       t('Checking <foo> brackets style in GESHIFILTER_BRACKETS_ANGLE mode'));
@@ -213,7 +221,9 @@ class GeshiFilterTest extends DrupalTest
       array(array($source_code, NULL, 0, 1, FALSE)),
       t('Checking [foo] brackets style in GESHIFILTER_BRACKETS_ANGLE mode'));
 
-    $this->drupalVariableSet('geshifilter_brackets', GESHIFILTER_BRACKETS_SQUARE);
+    $this->drupalVariableSet('geshifilter_tag_styles', array(
+      GESHIFILTER_BRACKETS_SQUARE => GESHIFILTER_BRACKETS_SQUARE,
+    ));
     $this->assertGeshiFilterHighlighting('<code language="cpp">'. $source_code .'</code>',
       array(array($source_code, NULL, 0, 1, FALSE)),
       t('Checking <foo> brackets style in GESHIFILTER_BRACKETS_SQUARE mode'));
