5 如何允许代码跨页 (breakable; across page) 并且让 caption 位于代码上方?

发布于 2025-06-11 00:15:02

在文档中插入代码的时候,我希望

  • 允许长代码自动跨页
  • 允许使用外部源代码文件
  • 支持代码语法高亮
  • caption 位于代码上方

如下是我使用 minted 的尝试,结果是跨页和题注都没有实现。
MWE.tex 如下。

\documentclass[a4paper,12pt]{ctexart}
\usepackage{minted}
\usepackage{float}
\usepackage{caption}
\begin{document}
    \begin{center}
    床前明月光,\\
    疑是地上霜。\\
    举头望明月,\\
    低头思故乡。\\
    \end{center}
    % TODO: 让代码从当前页继续,但如果当前页空间不足时自动换页
    \begin{listing}[htbp]
        % TODO: caption 位于代码上方
        \caption{代码}
        \label{code:besselj1}
        \inputminted{c}{besselj1.txt}
    \end{listing}
\end{document}

失败的排版效果如下。
MWE.png
代码 besselj1.txt 的内容随意,但保证一页 A4 放不下。

查看更多

关注者
0
被浏览
129
Sagittarius Rover
我要成为Typst糕手/(ㄒoㄒ)/~~

建议不要用「让代码就像文字一样,从当前页继续,但如果当前页空间不足时自动换页」这种表述,而是用「breakable listings」

太困了,只给例子,个人觉得tcb是比较好的实践了...

你要综合看tcolorboxlistings的文档

几个关键的option为:

  • listing remove caption=false
  • caption={Rust is Genshin Impact of coding}
  • captionpos=t(这是默认值,可调)
  • label={mycode}
\documentclass{article}
\usepackage[margin=1in]{geometry}
\usepackage{lipsum}
\usepackage[most]{tcolorbox}
\usepackage{hyperref}
\tcbuselibrary{listings}
\newtcbinputlisting{\mylisting}[2][]{%
    enhanced jigsaw,sharp corners,title={example~code},empty,left=1cm,breakable,%
    listing file={#2},listing only,listing remove caption=false,
    listing options={numbers=left,breaklines,basicstyle=\ttfamily,caption={Rust is Genshin Impact of coding},captionpos=t,label={mycode}},#1%
}
\begin{filecontents*}[overwrite]{temp.rs}
    use std::sync::{mpsc, Arc, Mutex};
    use std::thread;
    use std::time::Duration;
    
    struct ThreadPool {
        workers: Vec<Worker>,
        sender: mpsc::Sender<Message>,
    }
    
    impl ThreadPool {
        fn new(size: usize) -> Result<ThreadPool, PoolCreationError> {
            if size == 0 {
                return Err(PoolCreationError::InvalidSize);
            }
    
            let (sender, receiver) = mpsc::channel();
            let receiver = Arc::new(Mutex::new(receiver));
    
            let mut workers = Vec::with_capacity(size);
            for id in 0..size {
                workers.push(Worker::new(id, Arc::clone(&receiver)));
            }
    
            Ok(ThreadPool { workers, sender })
        }
    
        fn execute<F>(&self, f: F)
        where
            F: FnOnce() + Send + 'static,
        {
            let job = Box::new(f);
            self.sender.send(Message::NewJob(job)).unwrap();
        }
    }
    
    struct Worker {
        id: usize,
        thread: Option<thread::JoinHandle<()>>,
    }
    
    impl Worker {
        fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
            let thread = thread::spawn(move || loop {
                let message = receiver.lock().unwrap().recv().unwrap();
                match message {
                    Message::NewJob(job) => {
                        job();
                    }
                    Message::Terminate => break,
                }
            });
    
            Worker {
                id,
                thread: Some(thread),
            }
        }
    }
    
    enum Message {
        NewJob(Box<dyn FnOnce() + Send + 'static>),
        Terminate,
    }
    
    #[derive(Debug)]
    enum PoolCreationError {
        InvalidSize,
    }
    
    fn is_prime(n: u64) -> bool {
        if n <= 1 {
            return false;
        }
        for i in 2..=(n as f64).sqrt() as u64 {
            if n % i == 0 {
                return false;
            }
        }
        true
    }
    
    fn main() {
        
    }    
\end{filecontents*}
\begin{document}
I want to ref code \ref{mycode} here.
\lipsum[1]
\mylisting{temp.rs}
\lipsum[2]
\end{document}

image.png

2 个回答
追风少年
追风少年 2天前
这家伙很懒,什么也没写!

受到 @u70550 的启发,最后做出来满意的结果。目前的方案如下。

\documentclass{ctexart}
\usepackage[margin=3cm]{geometry}
\usepackage{listings}
\usepackage{xcolor}
\usepackage[colorlinks=true]{hyperref}

\definecolor{codegreen}{rgb}{0,0.5,0}
\definecolor{codeblue}{rgb}{0,0,0.8}
\definecolor{codegray}{rgb}{0.5,0.5,0.5}
\definecolor{codepurple}{rgb}{0.58,0,0.82}

% Set listing style
\lstdefinestyle{mystyle}{
    backgroundcolor=\color{white!95!black},
    commentstyle=\color{codegreen},
    keywordstyle=\color{codeblue},
    numberstyle=\tiny\color{codegray},
    stringstyle=\color{codepurple},
    basicstyle=\ttfamily\footnotesize,
    breakatwhitespace=false,         
    breaklines=true,
    captionpos=t,
    keepspaces=true,                 
    numbers=left,                    
    numbersep=5pt,                  
    showspaces=false,                
    showstringspaces=false,
    showtabs=false,                  
    tabsize=2,
    frame=single,
    belowcaptionskip=10pt
}
\lstset{style=mystyle}

\begin{filecontents*}[overwrite]{PackedFileDemo.c}
/*    This is the main file for the Packed File Demo program
which writes an Igor Pro 3.x packed experiment file.

See Igor Pro Tech Note PTN#003 for details.
*/

#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>                    // For offsetof macro.

#include "PackedFile.h"
#include "Variables.h"
#include "IgorBin.h"
#include "CrossPlatformFileIO.h"
#include "IgorSupport.h"

#include "PackedFileDemo.h"

static int
GetNextCommand(char* filePath)
{
    char input[1024];
    int command;
    int i;
    
    *filePath = 0;
    
    while(1) {
        printf("Command: ");
        if (fgets(input, sizeof(input)-1, stdin) != NULL) {
            char* p = strchr(input, '\n');            // Find new line character.
            if (p != NULL)
            *p = 0;                                // Remove new line character.
            for(i=0; i<5; i++)
            input[i] = toupper(input[i]);        // Convert command to upper case.
            if (strncmp(input, "READ ", 5) == 0) {
                command = 1;
                strcpy(filePath, input+5);
                break;
            }
            if (strncmp(input, "WRITE ", 6) == 0) {
                command = 2;
                strcpy(filePath, input+6);
                break;
            }
            if (strncmp(input, "QUIT", 4) == 0) {
                command = 3;
                break;
            }
        }
        printf("\n\n");
    }
    
    return command;
}

int
main(void)
{
    int command;
    char filePath[1024];
    char fullPathSample[32];
    char partialPathSample[32];
    int err;
    
    #ifdef WIN32
    strcpy(fullPathSample, "C:\\FolderA\\Test Packed File.pxp");
    strcpy(partialPathSample, ".\\Test Packed File.pxp");
    #else
    strcpy(fullPathSample, "hd:FolderA:Test Packed File");
    strcpy(partialPathSample, ":SamplesMac:Test Packed File");
    #endif
    
    printf("This program illustrates reading and writing Igor packed experiment files.\n\n");
    printf("To read a file, enter the following: Read <file path>\n\n");
    printf("To write a file, enter the following: Write <file path>\n\n");
    printf("<file path> can be either a full path (%s)\n", fullPathSample);
    printf("or a partial path relative to the folder containing this program (%s)\n", partialPathSample);
    printf("\n");
    printf("Here are some sample commands:\n");
    #ifdef WIN32
    printf("  Read Test Packed File.pxp\n");
    printf("  Read .\\Test Packed File.pxp\n");
    printf("  Write Test Packed File.pxp\n");
    #else
    printf("  Read Test Packed File\n");
    printf("  Read :Test Packed File\n");
    printf("  Write Test Packed File\n");
    #endif
    
    #ifdef WIN32
    printf("To quit the program, type Quit\n");
    #else
    printf("To quit the program, choose Quit from the file menu.\n");
    #endif
    
    while(1) {
        printf("\n");
        command = GetNextCommand(filePath);
        if (command == 1)
        err = ReadPackedFile(filePath);
        if (command == 2)
        err = WritePackedFile(filePath);
        if (command == 3) {
            #ifndef WIN32
            printf("Now you must choose Quit from the File menu to quit.\n");
            #endif
            break;
        }
    }
    
    return 0;    
}
\end{filecontents*}
\begin{document}
    \begin{center}
        静夜思\\[0.5em]
        〔唐代〕李白\\[0.5em]
        床前明月光,疑是地上霜。\\
        举头望明月,低头思故乡。\\
    \end{center}
    
    我想在此处引用代码 \ref{lst:maincode}。
    
    \lstinputlisting[language=C,caption={这是一段示例代码},label={lst:maincode}]{PackedFileDemo.c}
    
    我想唱歌。
    
    \begin{center}
        凉州词二首·其一\\[0.5em]
        〔唐代〕王之涣\\[0.5em]
        黄河远上白云间,一片孤城万仞山。\\
        羌笛何须怨杨柳,春风不度玉门关。\\
    \end{center}
\end{document}

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览