I don't like the concept. Better teach the users about proper use
instead of "fixing" it behind their backs.

I don't understand your concerns. I listed the 3 possibilities to fix this and why I have chosen the one I implemented. There is not other way to fix this, see also the last sentence of this mail. We also do this all the time: When you enter a "#" in normal text, it becomes in the background a "\#". The same is here, when you enter a "\" it becomes in the background now a "%5C% - valid LaTeX.

> /home/juergen/test\test/somefile.pdf is valid on Unix. How am I supposed to
> enter such a path?

\href has nothing to do with paths of OSes. It follows the definitions of URLs. So everything you can enter in this field is an URL, not a file path. When you use the option that a URL is a path to a file it is still an URL and therefore the resulting link will open the file via a URL browser and not the usual file explorer.

(Just for my interest: is /home/juergen/test\test/somefile.pdf equivalent to
                          /home/juergen/test\test\somefile.pdf ?)

> I'm not sure it's sound to just transcribe all the '\' to '/' without at 
least a warning. If for
> instance I'm pasting the name of a file, the '\' in the actual path should be 
really be
> transcribed as %5C.

You are completely right. I made a mistake that I escaped the "%" character in the URL field while it is allowed there. The attached patch fixes this and I also now correctly translate "\" to "%5C" so that
D:\TEst\1.jpg
leads now to
\href{file:D:%TEst%5C1.jpg}{D:\textbackslash{}TEst\textbackslash{}1.jpg}
This can be handled by IE and Firefox. Interestingly they both translate the "%5C" to "/". So in the end they do the same I did in my first patch and am now wondering why I was not allowed to.

regards Uwe
Index: insets/InsetHyperlink.cpp
===================================================================
--- insets/InsetHyperlink.cpp	(revision 28166)
+++ insets/InsetHyperlink.cpp	(working copy)
@@ -67,24 +67,39 @@
 int InsetHyperlink::latex(odocstream & os, OutputParams const & runparams) const
 {
 	docstring url = getParam("target");
+	docstring name = getParam("name");
 	static docstring const backslash = from_ascii("\\");
 	static docstring const braces = from_ascii("{}");
-	static char_type const chars_url[2] = {'%', '#'};
 	static char_type const chars_name[6] = {
 		'&', '_', '$', '%', '#', '^'};
 
+	// For the case there is no name given, the target is set as name.
+	// Do this before !url.empty() and !name.empty() to handle characters
+	// like the "%" correctly.
+	if (name.empty())
+		name = url;
+
 	// The characters in chars_url[] need to be changed to a command when
 	// they are in the url field.
 	if (!url.empty()) {
-		// the chars_url[] characters must be handled for both, url and href
-		for (int k = 0;	k < 2; k++) {
-			for (size_t i = 0, pos;
-				(pos = url.find(chars_url[k], i)) != string::npos;
-				i = pos + 2) {
-				url.replace(pos, 1, backslash + chars_url[k]);
-			}
+		// Replace the "\" character by its ASCII code according to the URL specifications
+		// because "\" is not allowed in URLs and by \href. Only do this when the
+		// following character is not also a "\", because "\\" is valid code
+		for (size_t i = 0, pos;
+			(pos = url.find('\\', i)) != string::npos;
+			i = pos + 2) {
+			if (url[pos + 1] != '\\')
+				url.replace(pos, 1, from_ascii("%5C"));
 		}
-
+		// "#" needs to be escapes to "\#", therefore the treatment
+		// of "\" must be done before
+		for (size_t i = 0, pos;
+			(pos = url.find('#', i)) != string::npos;
+			i = pos + 2) {
+			if (url[pos + 1] != '\\')
+				url.replace(pos, 1, from_ascii("\\#"));
+		}
+		
 		// add "http://"; when the type is web (type = empty)
 		// and no "://" or "run:" is given
 		docstring type = getParam("type");
@@ -95,12 +110,9 @@
 
 	} // end if (!url.empty())
 
-	docstring name = getParam("name");
-
 	// The characters in chars_name[] need to be changed to a command when
 	// they are in the name field.
 	if (!name.empty()) {
-
 		// handle the "\" character, but only when the following character
 		// is not also a "\", because "\\" is valid code
 		docstring const textbackslash = from_ascii("\\textbackslash{}");
@@ -110,6 +122,9 @@
 			if (name[pos + 1] != '\\')
 				name.replace(pos, 1, textbackslash);
 		}
+		// The characters in chars_name[] need to be changed to a command when
+		// they are in the name field.
+		// Therefore the treatment of "\" must be the first thing
 		for (int k = 0;	k < 6; k++) {
 			for (size_t i = 0, pos;
 				(pos = name.find(chars_name[k], i)) != string::npos;
@@ -130,9 +145,8 @@
 	if (runparams.moving_arg)
 		os << "\\protect";
 
-	//for the case there is no name given, the target is set as name
-	os << "\\href{" << getParam("type") << url << "}{"
-		<< (name.empty()? url : name) << '}';
+	// output the ready \href command
+	os << "\\href{" << getParam("type") << url << "}{" << name << '}';
 
 	return 0;
 }

Reply via email to