Re[2]: Incorrect newline counters
Dmitry Koteroff <[email protected]>
| Newsgroups | gmane.comp.php.smarty.devel |
|---|---|
| Message-ID | <[email protected]> |
MO> The important thing here is that the template source matches
MO> _exactly_ to the template output, which includes newlines.
MO> This may not be so important with HTML output, but things
MO> like e-mail templates it is crucial.
Oh. First serious argument, wow.
MO> PHP's behavior is to eat newline characters after ?> tags.
MO> This is fine for your typical imbedded HTML programs, but for
MO> template engines like Smarty it causes problems. Therefore to
MO> make template output identical to template source, a lot of
MO> careful work was done to add newline characters after ?>
I'd like to write up Larry Wall's (I agreed with him) opinion
about all this situation. It seems to me that we need to
automatize this, but not insert \n's manually. Computers is made
to make all jogtrot work, to free programmer from it. For
programmer the word "carefull" in most cases means "wrong
designed".
MO> tags to essentially "undo" this PHP feature. When you say you
MO> remove unnecessary \n's, this leads me to think it will break
MO> output, meaning it will butt lines together that really need
MO> to be separate. Have you tested it?
I have spent half an our and now it is OK. See full description
below.
MO> As for line number counting in the compiled PHP files, I
MO> don't see how that can or should correspond to line numbers
MO> in the template source. If we can figure out a way to make
MO> the line numbers correspond _and_ make template output
MO> identical to source, then I don't see a problem with it. But
No problem, here is the patch (attached).
Idea of method:
- In each text block we insert:
$text = preg_replace("/^([\r\n]+)/s", '<?php echo "$1"; ?>', $text);
- In code blocks we insert:
$text = preg_replace("/([\r\n]+)/s", '<?php $1?>', $text);
That's almost all. No need of $_additional_newline.
I have a little question. Let's consider piece of code
(t_controller does not modify or trim its body):
{t_controller src="Orphus_Test" name="date" format="Y-m-d"}
{$date}
{/t_controller}
<hr>
Please say which result should it THEORETICALLY output?
1. "2004-06-01\n\n<hr>"
or
2. "2004-06-01\n<hr>"
Which one?
-------------------------------------------------------
Roots (history) of the problem
PHP ignores \n's after ?>:
<?php echo "hello"?>
world
Result will be "helloworld" (no \n).
In contrast of PHP, Smarty DOES insert \n's after constructions
if they were there in the template:
{"hello"}
world
Result will be: "hello\nworld" (\n is saved).
My previous patch had not considered this situation, so Smarty's
constructions began to work like PHP constructions (stripping
\n's after "}"). Today I have totally (hope) fixed this.
So, output of original Smarty and output of patched version is
IDENTICALL, in all cases. But line numbers synchronization is now
OK: compiled code matches source template line-by-line too.
Main goal - giving error message with line number (E_NOTICE, for
example) while executing the template you my directly watch into
the SOURCE template and search for given line number in it.
--
Best regards,
Dmitry Koteroff.
--
Smarty Development Mailing List (http://smarty.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
Smarty_Compiler_diff.txt
(text/plain, 7.2 KB)
--- Distrib.orig/libs/Smarty_Compiler.class.php Tue Feb 17 19:55:24 2004
+++ Distrib/libs/Smarty_Compiler.class.php Tue Jun 01 19:22:19 2004
@@ -255,8 +255,9 @@
. "'"
, $source_content);
-
+
/* Gather all template tags. */
preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $source_content, $_match);
$template_tags = $_match[1];
+ $template_tags_sp = $_match[0];
/* Split content by template tags to obtain non-template content. */
$text_blocks = preg_split("!{$ldq}.*?{$rdq}!s", $source_content);
@@ -276,5 +277,5 @@
if ($this->php_handling == SMARTY_PHP_PASSTHRU) {
/* echo php contents */
- $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);
+ $text_blocks[$curr_tb] = preg_replace('/%%%SMARTYSP'.$curr_sp.'%%%([\r\n]*)/s', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'."\1"; ?>', $text_blocks[$curr_tb]);
} else if ($this->php_handling == SMARTY_PHP_QUOTE) {
/* quote php tags */
@@ -285,5 +286,5 @@
} else {
/* SMARTY_PHP_ALLOW, but echo non php starting tags */
- $sp_match[1][$curr_sp] = preg_replace('%(<\?(?!php|=|$))%i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]);
+ $sp_match[1][$curr_sp] = preg_replace('%(<\?(?!php|=|$))([\r\n]*)%i', '<?php echo \'\\1\'."$3"?>', $sp_match[1][$curr_sp]);
$text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]);
}
@@ -296,6 +297,13 @@
for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) {
$this->_current_line_no += substr_count($text_blocks[$i], "\n");
+ if ($this->_strip_depth || 0) {
+ $text_blocks[$i] = preg_replace("/[\t ]+(?=\r?\n)|(?<=\n)[\t ]+/s", '', $text_blocks[$i]);
+ $text_blocks[$i] = preg_replace("/([\r\n]+)/s", '<?php $1?'.'>', $text_blocks[$i]);
+ }
$compiled_tags[] = $this->_compile_tag($template_tags[$i]);
$this->_current_line_no += substr_count($template_tags[$i], "\n");
+ if ($template_tags[$i] == "strip" || $template_tags[$i] == "/strip") {
+ $compiled_tags[count($compiled_tags)-1] = "";
+ }
}
if (count($this->_tag_stack)>0) {
@@ -309,23 +317,16 @@
/* Interleave the compiled contents and text blocks to get the final result. */
for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
- if ($compiled_tags[$i] == '') {
- // tag result empty, remove first newline from following text block
- $text_blocks[$i+1] = preg_replace('!^(\r\n|\r|\n)!', '', $text_blocks[$i+1]);
+ $lT = substr_count($template_tags_sp[$i], "\n");
+ $lC = substr_count($compiled_tags[$i], "\n");
+ if ($lC > $lT) {
+ $compiled_tags[$i] = trim(preg_replace('/[\r\n]+/s', ' ', $compiled_tags[$i]));
+ $lC = 0;
}
- $compiled_content .= $text_blocks[$i].$compiled_tags[$i];
+ $compiled_tags[$i] .= str_repeat("<?php\n?".">", max($lT-$lC, 0));
+ $compiled_content .= $text_blocks[$i].$compiled_tags[$i];
+ $text_blocks[$i+1] = preg_replace('/^([\r\n]+)/s', '<?php echo "$1"; ?'.'>', $text_blocks[$i+1]);
}
$compiled_content .= $text_blocks[$i];
- /* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */
- if (preg_match_all("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $compiled_content, $_match)) {
- $strip_tags = $_match[0];
- $strip_tags_modified = preg_replace("!{$ldq}/?strip{$rdq}|[\t ]+$|^[\t ]+!m", '', $strip_tags);
- $strip_tags_modified = preg_replace('![\r\n]+!m', '', $strip_tags_modified);
- for ($i = 0, $for_max = count($strip_tags); $i < $for_max; $i++)
- $compiled_content = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s",
- $this->_quote_replace($strip_tags_modified[$i]),
- $compiled_content, 1);
- }
-
// remove \n from the end of the file, if any
if (($_len=strlen($compiled_content)) && ($compiled_content{$_len - 1} == "\n" )) {
@@ -338,5 +339,5 @@
// remove unnecessary close/open tags
- $compiled_content = preg_replace('!\?>\n?<\?php!', '', $compiled_content);
+ $compiled_content = preg_replace('!\?'.'><\?php!', '', $compiled_content);
// run compiled template through postfilter functions
@@ -355,6 +356,6 @@
// put header at the top of the compiled template
- $template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n";
- $template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n";
+ $template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."";
+ $template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>";
/* Emit code to load needed plugins. */
@@ -369,5 +370,5 @@
}
$_plugins_params .= '))';
- $plugins_code = "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n";
+ $plugins_code = "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php'); smarty_core_load_plugins($_plugins_params, \$this); ?>";
$template_header .= $plugins_code;
$this->_plugin_info = array();
@@ -376,5 +377,5 @@
if ($this->_init_smarty_vars) {
- $template_header .= "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n";
+ $template_header .= "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.assign_smarty_interface.php'); smarty_core_assign_smarty_interface(null, \$this); ?>";
$this->_init_smarty_vars = false;
}
@@ -412,5 +413,5 @@
$_return = $this->_parse_var_props($tag_command . $tag_modifier, $this->_parse_attrs($tag_args));
if(isset($_tag_attrs['assign'])) {
- return "<?php \$this->assign('" . $this->_dequote($_tag_attrs['assign']) . "', $_return ); ?>\n";
+ return "<?php \$this->assign('" . $this->_dequote($_tag_attrs['assign']) . "', $_return ); ?>";
} else {
return "<?php echo $_return; ?>" . $this->_additional_newline;