使用中解释的方法https://tex.stackexchange.com/a/213413/218142我可以在用 定义的列表环境中单击代码lstnewenvironment
。学生从中剪切并粘贴他们的代码GlowScript.org进入newglowscriptblock
环境,提供一个标题和一个 URL,这样当我单击代码时,我就会进入他们的程序并运行它。我可能可以保持原样,但是有没有办法将其封装到适当定义的环境中?换句话说,有没有办法将框的使用包含在环境定义中,或者定义一个新环境,使这一切就像将代码剪切并粘贴到环境中一样简单?(我定义了一种样式,lstdefinestyle
但我没有在这里包含它。)我还希望能够单击图形上的任意位置,而不仅仅是实际代码。这也可以实现吗?
这是我的 MWE 及其输出。
\documentclass{article}
\usepackage{listings}
\lstnewenvironment{newglowscriptblock}[3]{%
\lstset{caption={#1},label={#2}}}{}
\usepackage{hyperref}
\hypersetup{pdfborder=0 0 0}
\begin{document}
% See https://tex.stackexchange.com/a/213413/218142
\newsavebox\lstA
\begin{lrbox}{\lstA}
\begin{newglowscriptblock}{Problem 37 Code}{pref2}{}
GlowScript 3.0 VPython
# a Young's modulus problem
Lo = 3 # wire's original length in m
d = 3e-3 # wire's diameter in m
g = 9.8 # surface grav. field strength in N/kg
m = 10 # ball's mass in kg
Y = 2e11 # steel's Young's modulus in N/m^2
# Find DeltaL, the amount the wire stretches.
area = (pi*d**2)/4
Force = m*g
DeltaL = (Force*Lo)/(area*Y)
print ("The wire stretches by ",DeltaL," m")
\end{newglowscriptblock}
\end{lrbox}
% The URL here is would the #3 in the definition of newglowscriptenvironment
\href{https://google.com}{\usebox{\lstA}}
\end{document}
答案1
这可能有用 - 但是 - 没有任何保证!;-)
\documentclass{article}
\usepackage{listings}
\usepackage[colorlinks=true]{hyperref}
%\usepackage[colorlinks=false]{hyperref}
\makeatletter
\newsavebox\newglowscriptblockTempBox
\newcommand\newglowscriptblockURL{}%
\newcommand\newglowscriptblockWrapInPartopsep[1]{%
\vskip\partopsep#1\vskip\partopsep
}%
\lstnewenvironment{newglowscriptblock}[3]{%
\gdef\newglowscriptblockURL{#3}%
\setbox\newglowscriptblockTempBox\hbox{\begingroup\aftergroup}%
\lstset{caption={#1},label={#2}}%
}{%
\endgroup
\hypersetup{hidelinks}%
\ifvmode\endgraf\expandafter\newglowscriptblockWrapInPartopsep\else\endgraf\expandafter\@firstofone\fi
{%
\vskip\topsep
\noindent
\expandafter\href\expandafter{\newglowscriptblockURL}{\usebox{\newglowscriptblockTempBox}}%
\endgraf
\vskip\topsep
}%
}%
% Make sure hyperref's \href gets its argument "normalized
\@ifdefinable\newglowscriptblock@@{%
\let\newglowscriptblock@@=\newglowscriptblock@
\renewcommand\newglowscriptblock@[2]{\hyper@normalise{\newglowscriptblock@@\unexpanded{{#1}{#2}}}}%
}%
\makeatother
\begin{document}
\lstlistoflistings
\newpage
Some text. Some text.
Some text. Some text.
\begin{newglowscriptblock}{Problem 37 Code}{pref2}{https://google.com}
GlowScript 3.0 VPython
# a Young's modulus problem
Lo = 3 # wire's original length in m
d = 3e-3 # wire's diameter in m
g = 9.8 # surface grav. field strength in N/kg
m = 10 # ball's mass in kg
Y = 2e11 # steel's Young's modulus in N/m^2
# Find DeltaL, the amount the wire stretches.
area = (pi*d**2)/4
Force = m*g
DeltaL = (Force*Lo)/(area*Y)
print ("The wire stretches by ",DeltaL," m")
\end{newglowscriptblock}
Some text. Some text.
Some text. Some text.
\newpage
nameref-link to listing: \nameref{pref2}
ref-link to listing: \ref{pref2}
pageref-link to listing: \pageref{pref2}
autoref-link to listing: \autoref{pref2}
\end{document}
2020 年 10 月 21 日补遗
在 2020 年 10 月 20 日的评论中,您问道:
如果我不想提供 URL,有没有办法抑制 hyperref 关于空目标的警告,或者我可以提供一些不会使代码在用鼠标单击时突出显示的东西?
我使用的 pdf 查看器在用鼠标单击时不会突出显示内容。我猜想突出显示不是 pdf 文件的原因,而是 pdf 查看程序中“硬连线”的功能。
如果您不介意改变环境参数的顺序,使得保存 URL 的参数不是第三个而是第一个,那么您可以将该参数设为可选,并使用空默认值。
您需要采取一些技巧来使 URL 参数标准化以适应 hyperref。否则,您无法#
在 URL 中使用类似字符。
\newglowscriptblockURL
然后,您可以添加分叉来检查从 URL 参数定义的宏的扩展是否产生“空白”,即空或仅显式空格标记,并且\href
仅在不是这种情况时才应用。这样,如果未提供现在可选的 URL 参数或提供为空,则不会尝试创建超链接:
\documentclass{article}
\usepackage{listings}
\usepackage[colorlinks=true]{hyperref}
%\usepackage[colorlinks=false]{hyperref}
\makeatletter
% Infrastructure for "hyperref-normalizing" an optional argument of a \lstnewenvironment:
\begingroup
\catcode`\^^A=14 %
\catcode`\^^M\active^^A
\catcode`\%\active^^A
\@ifdefinable\hyper@@normaliseoptarg{^^A
\gdef\hyper@@normaliseoptarg#1#2#3]{^^A
\edef\Hy@tempa{^^A
\endgroup\noexpand#1[{\Hy@RemovePercentCr#3%^^M\@nil}]^^A
}^^A
\Hy@tempa^^A
}^^A
}^^A
\endgroup
\newcommand\MY@exchange[2]{#2#1}%
\expandafter\newcommand\expandafter*\expandafter\hyper@normaliseoptarg\expandafter{%
\romannumeral0%
\expandafter\MY@exchange\expandafter{\hyper@normalise}{%
\@firstofone{\expandafter} %
\MY@exchange{\let\hyper@@normalise=\hyper@@normaliseoptarg}%
}%
}%
\newcommand\lstenv@testhyper@normalizeopt[2]{%
\@ifnextchar[{\catcode \active 5\relax\hyper@normaliseoptarg{\lstenv@testopt\noexpand#1{#2}}}%
{\hyper@normaliseoptarg{#1}[{#2}]}%
}%
% end of Infrastructure for "hyperref-normalizing" an optional argument of a \lstnewenvironment.
\newsavebox\newglowscriptblockTempBox
\newcommand\newglowscriptblockURL{}%
\newcommand\newglowscriptblockWrapInPartopsep[1]{%
\vskip\partopsep#1\vskip\partopsep
}%
\lstnewenvironment{newglowscriptblock}[3][]{%
\gdef\newglowscriptblockURL{#1}%
\setbox\newglowscriptblockTempBox\hbox{\begingroup\aftergroup}%
\lstset{caption={#2},label={#3}}%
}{%
\endgroup
\ifx\newglowscriptblockURL\empty\else\hypersetup{hidelinks}\fi
\ifvmode\endgraf\expandafter\newglowscriptblockWrapInPartopsep\else\endgraf\expandafter\@firstofone\fi
{%
\vskip\topsep
\noindent
\ifcat $\detokenize\expandafter\expandafter\expandafter{\expandafter\@firstoftwo\newglowscriptblockURL{}.}$%
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\@firstofone}%
{\expandafter\href\expandafter{\newglowscriptblockURL}}%
{\usebox{\newglowscriptblockTempBox}}%
\endgraf
\vskip\topsep
}%
}%
% Make sure hyperref's \href gets its argument "hyperref-normalized" by replacing
% \lstenv@testopt with \lstenv@testhyper@normalizeopt
% in the definition of \newglowscriptblock@.
\expandafter\renewcommand\expandafter*\expandafter\newglowscriptblock@\expandafter{%
\romannumeral0%
\expandafter\MY@exchange\expandafter{%
\csname\string\newglowscriptblock@\endcsname{}%<-the default for the opt arg is between these braces. The default is empty.
}{ %
\ifx\protect\@typeset@protect
\expandafter\lstenv@testhyper@normalizeopt
\else
\@x@protect\newglowscriptblock@
\fi
}%
}%
\makeatother
\begin{document}
\lstlistoflistings
\newpage
Some text. Some text.
Some text. Some text.
The optional argument is not empty, thus the environment is a hyperlink. %
\begin{newglowscriptblock}[https://google.com#Weird]{Problem 37 Code}{pref2}
GlowScript 3.0 VPython
# a Young's modulus problem
Lo = 3 # wire's original length in m
d = 3e-3 # wire's diameter in m
g = 9.8 # surface grav. field strength in N/kg
m = 10 # ball's mass in kg
Y = 2e11 # steel's Young's modulus in N/m^2
# Find DeltaL, the amount the wire stretches.
area = (pi*d**2)/4
Force = m*g
DeltaL = (Force*Lo)/(area*Y)
print ("The wire stretches by ",DeltaL," m")
\end{newglowscriptblock}
The optional argument is not empty, thus the environment is a hyperlink.
Some text. Some text.
Some text. Some text.
\newpage
Some text. Some text.
Some text. Some text.
The optional argument is empty, thus the environment is not a hyperlink.
\begin{newglowscriptblock}{Problem 37 Code}{pref3}
GlowScript 3.0 VPython
# a Young's modulus problem
Lo = 3 # wire's original length in m
d = 3e-3 # wire's diameter in m
g = 9.8 # surface grav. field strength in N/kg
m = 10 # ball's mass in kg
Y = 2e11 # steel's Young's modulus in N/m^2
# Find DeltaL, the amount the wire stretches.
area = (pi*d**2)/4
Force = m*g
DeltaL = (Force*Lo)/(area*Y)
print ("The wire stretches by ",DeltaL," m")
\end{newglowscriptblock}
The optional argument is empty, thus the environment is not a hyperlink.
Some text. Some text.
Some text. Some text.
\newpage
nameref-link to listing pref2: \nameref{pref2}
ref-link to listing pref2: \ref{pref2}
pageref-link to listing pref2: \pageref{pref2}
autoref-link to listing pref2: \autoref{pref2}
nameref-link to listing pref3: \nameref{pref3}
ref-link to listing pref3: \ref{pref3}
pageref-link to listing pref3: \pageref{pref3}
autoref-link to listing pref3: \autoref{pref3}
\end{document}
答案2
为了参考,我附上了这个答案。我发现tcolorbox
只需一个命令就可以很简单地完成此操作。框的整个内部都是可点击的(当然,在下面的屏幕截图中它不起作用,但它可以在您的文档中工作),并且可以将 URL 设置为新命令的可选参数。
% !TEX program = lualatexmk
% !TEX encoding = UTF-8 Unicode
\documentclass{article}
\usepackage[left=1.00in,right=1.00in]{geometry}
\usepackage[most]{tcolorbox} % loads the listings library
\usepackage{hyperref}
\hypersetup{colorlinks=true}
\definecolor{gsbggray} {rgb}{0.90,0.90,0.90} % background gray
\definecolor{gsgray} {rgb}{0.30,0.30,0.30} % gray
\definecolor{gsgreen} {rgb}{0.00,0.60,0.00} % green
\definecolor{gsorange} {rgb}{0.80,0.45,0.12} % orange
\definecolor{gspeach} {rgb}{1.00,0.90,0.71} % peach
\definecolor{gspearl} {rgb}{0.94,0.92,0.84} % pearl
\definecolor{gsplum} {rgb}{0.74,0.46,0.70} % plum
\lstdefinestyle{vpython}{% % style for listings
backgroundcolor=\color{gsbggray},% % background color
basicstyle=\footnotesize,% % default style
breakatwhitespace=true% % break at whitespace
breaklines=true,% % break long lines
captionpos=b,% % position caption
classoffset=1,% % STILL DON'T UNDERSTAND THIS
commentstyle=\color{gsgray},% % font for comments
deletekeywords={print},% % delete keywords from the given language
emph={self,cls,@classmethod,@property},% % words to emphasize
emphstyle=\color{gsorange}\itshape,% % font for emphasis
escapeinside={(*@}{@*)},% % add LaTeX within your code
frame=tb,% % frame style
framerule=2.0pt,% % frame thickness
framexleftmargin=5pt,% % extra frame left margin
%identifierstyle=\sffamily,% % style for identifiers
keywordstyle=\sffamily\color{gsplum},% % color for keywords
language=Python,% % select language
linewidth=\linewidth,% % width of listings
morekeywords={% % VPython/GlowScript specific keywords
__future__,abs,acos,align,ambient,angle,append,append_to_caption,%
append_to_title,arange,arrow,asin,astuple,atan,atan2,attach_arrow,%
attach_trail,autoscale,axis,background,billboard,bind,black,blue,border,%
bounding_box,box,bumpaxis,bumpmap,bumpmaps,camera,canvas,caption,capture,%
ceil,center,clear,clear_trail,click,clone,CoffeeScript,coils,color,combin,%
comp,compound,cone,convex,cos,cross,curve,cyan,cylinder,data,degrees,del,%
delete,depth,descender,diff_angle,digits,division,dot,draw_complete,%
ellipsoid,emissive,end_face_color,equals,explog,extrusion,faces,factorial,%
False,floor,follow,font,format,forward,fov,frame,gcurve,gdisplay,gdots,%
get_library,get_selected,ghbars,global,GlowScript,graph,graphs,green,gvbars,%
hat,headlength,headwidth,height,helix,hsv_to_rgb,index,interval,keydown,%
keyup,label,length,lights,line,linecolor,linewidth,logx,logy,lower_left,%
lower_right,mag,mag2,magenta,make_trail,marker_color,markers,material,%
max,min,mouse,mousedown,mousemove,mouseup,newball,norm,normal,objects,%
offset,one,opacity,orange,origin,path,pause,pi,pixel_to_world,pixels,plot,%
points,pos,pow,pps,print,print_function,print_options,proj,purple,pyramid,%
quad,radians,radius,random,rate,ray,read_local_file,readonly,red,redraw,%
retain,rgb_to_hsv,ring,rotate,round,scene,scroll,shaftwidth,shape,shapes,%
shininess,show_end_face,show_start_face,sign,sin,size,size_units,sleep,%
smooth,space,sphere,sqrt,start,start_face_color,stop,tan,text,textpos,%
texture,textures,thickness,title,trail_color,trail_object,trail_radius,%
trail_type,triangle,trigger,True,twist,unbind,up,upper_left,upper_right,%
userpan,userspin,userzoom,vec,vector,vertex,vertical_spacing,visible,%
visual,vpython,VPython,waitfor,white,width,world,xtitle,yellow,yoffset,%
ytitle%
},%
morekeywords={print,None,TypeError},% % additional keywords
morestring=[b]{"""},% % treat triple quotes as strings
numbers=left,% % where to put line numbers
numbersep=10pt,% % how far line numbers are from code
numberstyle=\bfseries\tiny,% % set to 'none' for no line numbers
showstringspaces=false,% % show spaces in strings
showtabs=false,% % show tabs within strings
stringstyle=\color{gsgreen},% % color for strings
upquote=true,% % how to typeset quotes
}%
\NewTCBListing[auto counter,list inside=gsprogs]{tcbglowscriptblock}{ O{} D(){glowscript.org} m }{%
breakable,%
center,%
code = \newpage,%
%derivpeach,%
enhanced,%
hyperurl interior = https://#2,%
label = {gs:\thetcbcounter},%
left = 8mm,%
list entry = \texttt{GlowScript} Program \thetcbcounter: #3,%
listing only,%
listing style = vpython,%
nameref = #3,%
title = \texttt{GlowScript} Program \thetcbcounter: #3,%
width = 0.9\textwidth,%
#1,
}%
\begin{document}
\begin{tcbglowscriptblock}(google.com){A short \texttt{GlowScript} Program}
GlowScript 3.0 vpython
scene.width = 400
scene.height = 760
# constants and data
g = 9.8 # m/s^2
mball = 0.03 # kg
Lo = 0.26 # m
ks = 1.8 # N/m
deltat = 0.01 # s
# objects (origin is at ceiling)
ceiling = box(pos=vector(0,0,0), length=0.2, height=0.01,
width=0.2)
ball = sphere(pos=vector(0,-0.3,0),radius=0.025,
color=color.orange)
spring = helix(pos=ceiling.pos, axis=ball.pos-ceiling.pos,
color=color.cyan,thickness=0.003,coils=40,
radius=0.010)
# initial values
pball = mball * vector(0,0,0) # kg m/s
Fgrav = mball * g * vector(0,-1,0) # N
t = 0
# improve the display
scene.autoscale = False # turn off automatic camera zoom
scene.center = vector(0,-Lo,0) # move camera down
scene.waitfor('click') # wait for a mouse click
# initial calculation loop
# calculation loop
while t < 10:
rate(100)
# we need the stretch
s = mag(ball.pos) - Lo
# we need the spring force
Fspring = ks * s * -norm(spring.axis)
Fnet = Fgrav + Fspring
pball = pball + Fnet * deltat
ball.pos = ball.pos + (pball / mball) * deltat
spring.axis = ball.pos - ceiling.pos
t = t + deltat
\end{tcbglowscriptblock}
The program \ref{gs:1} is nice. It's called \nameref{gs:1} on page \pageref{gs:1}.
\end{document}