Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I would like to be able to allow line breaking on /'s, ?, and &'s.

I understand I should change the \catcode's of those letters, but I don't want them to be global, but instead restricted to inside of the macro. This is what I have tried:

\def\url{%
  \begingroup%
    \def\urlaux##1{##1\endgroup}%
    \catcode`\&=13
    \def&{\penalty0\char`\&}%
    \urlaux}

\url{http://tex.stackexchange.com/some/long/path/and?someBizarreLong=param&andYetAnotherSuchBizarreLong=param}
\bye

but TeX tells me that & is inaccessible on its \definition

I remember reading something like: “The catcode change is not being done during the execution of the macro, but during reading of it”, or something along those lines.

But I have tried moving the definition of the ampersand to inside of the \urlaux, for example, without success.

How could I make it accessible?

share|improve this question
    
You need to alter the catcode when making the definition: here you've tokenized \url with & as the tab alignment char. –  Joseph Wright May 15 at 11:02
    
@Joseph: Yes, I've read that exact same sentence now a quadzillion times, yet I gain no insight from it as to how to proceed. –  morbusg May 15 at 11:05
add comment

5 Answers 5

up vote 8 down vote accepted

TeX assigns category code when an argument is grabbed and tokenized. As a result, inside your definition of \url, & has catcode 'tab alignment' (assuming normal rules apply). You can only \def an active char, so this step fails as you've observed.

What you need to do is make sure that the definition of \url contains an active &:

\begingroup
\catcode`\&=\active
\gdef\url{%
  \begingroup%
    \def\urlaux##1{##1\endgroup}%
    \catcode`\&=\active
    % Catcode of & that is important here is when \url is defined:
    \def&{\penalty0\char`\&}% 
    \urlaux}
\endgroup

\url{http://tex.stackexchange.com/some/long/path/and?someBizarreLong=param&andYetAnotherSuchBizarreLong=param}
\bye

Notice that you still need to alter the catcode of & when grabbing the argument of \urlaux too! (The entire 'trick' here depends on not grabbing the argument using \url as that will tokenize at the wrong time.) That means that reordering to say

\begingroup
\catcode`\&=\active
\gdef\url{%
  \begingroup%
    % Catcode of & that is important here is when \url is defined:
    \def&{\penalty0\char`\&}% 
    \def\urlaux##1{##1\endgroup}%
    \catcode`\&=\active
    \urlaux}
\endgroup

will also work: the second catcode change is about the grabbed argument and has nothing to do with the definition of & that we are using.

share|improve this answer
    
Thanks! Though, am I right in arguing that \url has no argument? –  morbusg May 15 at 11:12
    
@morbusg Yes, I'll clarify –  Joseph Wright May 15 at 11:54
add comment

It is much better not to change catcodes mid document but instead change the mathcode (as then it works as much as possibe even in macro arguments) this is what url.sty does

url.sty uses hardly any latex so works with plain tex with a bit of encouragement, or you could simply edit the file to remove the latex bits rather than defining stubs as here

enter image description here

\catcode`\@=11
\def\@namedef#1{\expandafter\def\csname#1\endcsname}
\def\@ifundefined#1#2#3{%
\expandafter\ifx\csname#1\endcsname\relax
#2\else#3\fi}
\let\protect\relax
\let\ProcessOptions\relax
\def\DeclareOption#1#2{}
\def\@makeother#1{\catcode`#1=12 }
\def\@ifnextchar#1#2#3{#2}
\def\@empty{}
\def\@firstoftwo#1#2{#1}
\def\@secondoftwo#1#2{#2}
\newcount\@tempcnta
\input url.sty
\def\UrlFont{\tt}

\hrule

abc abc \url{http://www.example.com/one/two/three.html}  abc
abc abc \url{http://www.example.com/one/two/three.html}  abc
abc abc \url{http://www.example.com/one/two/three.html}  abc
abc abc \url{http://www.example.com/one/two/three.html}  abc
abc abc \url{http://www.example.com/one/two/three.html}  abc

\bye
share|improve this answer
    
Thanks. How does \mathcode come into play? –  morbusg May 15 at 12:43
2  
Donald's trick in url.sty is to make characters by mathcode"8000 (same as ') which means then you can access their active definition without making them active. furthermore linebreaking is allowed with two differemt strengths eg at / and at . by making characters be \mathrel or \mathbin then the whole URL is set in inline math mode –  David Carlisle May 15 at 13:02
add comment

Use eplain:

\input eplain
\beginpackages
\usepackage{url}
\endpackages

\rightskip=10em minus 8em % avoid overfull box
\url{http://tex.stackexchange.com/some/long/path/and?someBizarreLong=param&andYetAnotherSuchBizarreLong=param}

\bye

enter image description here

Your (simplistic) definition can be corrected with

\begingroup
\catcode`\&=\active % we want an active & in the replacement text of \url

\gdef\url{% \gdef because we're in a group
  \begingroup
  \def\urlaux##1{##1\endgroup}%
  \catcode`\&=\active
  \def&{\penalty0\char`\&}%
  \urlaux}
\endgroup

\url{http://tex.stackexchange.com/some/long/path/and?someBizarreLong=param&andYetAnotherSuchBizarreLong=param}
\bye
share|improve this answer
    
I did try using url.sty via eplain, but I couldn't get it to work (I guess my other definitions somehow break it). But I didn't really need all the bling bling of the package, so I thought I'd just keep it really simple. Thanks, though! –  morbusg May 15 at 12:41
add comment

Package url can also be used with plain TeX via the help of miniltx:

\input miniltx.tex
\input url.sty
\resetatcatcode

\url{http://tex.stackexchange.com/questions/177340/typesetting-url-uri-iri-in-plain-tex}

\bye

Result

share|improve this answer
add comment

The opmac package (intended for plainTeX) implements \url too:

\input opmac

\rightskip=0pt plus5em
\url{http://tex.stackexchange.com/some/long/path/and?someBizarreLong=param&andYetAnotherSuchBizarreLong=param}

\end

Of course, you needn't use whole opmac.tex but you can be inspired by the macro \url from it where you can see:

\def\url#1{{\def\tmpb{#1}%
   \replacestrings{//}{{\urlskip\urlslashslash\urlbskip}}%
   \replacestrings{/}{{\urlskip/\urlbskip}}%
   \replacestrings{.}{{\urlskip.\urlbskip}}%
   \replacestrings{?}{{\urlskip?\urlbskip}}%
   \replacestrings{=}{{\urlskip=\urlbskip}}%
   \replacestrings{~}{{\char`\~}}%
   \replacestrings{_}{{\char`\_}}%
   \replacestrings{^}{{\char`\^}}%
   \replacestrings{\\}{\bslash}%
   \replacestrings{\{}{{\char`\{}}%
   \replacestrings{\}}{{\char`\}}}%
   \replacestrings{&}{{\urlbskip\char`\& \urlskip}}%
   \def\|{}\ulink[#1]{\urlfont\tmpb}%
}}

It means that the \url is implemetned by \replacestrings which is better than catcode changing because catcode changing does not work when whole \url{...} is a part of a parameter of another macro.

If you decided to do catcode manipulating then you can use \adef macro which is stolen from opmac.tex too:

\def\adef#1{\catcode`#1=13 \bgroup \lccode`\~=`#1\lowercase{\egroup\def~}}

\def\url{%
   \begingroup%
   \adef&{\penalty0\char`\&}% 
   \def\urlaux##1{##1\endgroup}%
   \urlaux}

You can see that the catcode setting is more simple.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.