Skip to content

Forward and Backward synchronizations failed when path contains non-ASCII characters #5410

@unbadfish

Description

@unbadfish

SumatraPDF version

  • Version v3.7.17694 64-bit Pre-release

Describe the bug
When the file path contains non-ASCII characters (e.g., Chinese characters), both forward and backward synchronization fail.
Corrected: In backward case, a info message appears: “No synchronization info at this position”.

To Reproduce

  1. Create a TeX file whose path includes non-ASCII characters, and compile it. See attachment below. (tested with VS Code + LaTeX Workshop)
  2. Trigger forward sync from VS Code to SumatraPDF — the sync fails, and there are (always) no purple highlight appears.
  3. Double-click on text in SumatraPDF to trigger backward sync — the sync (always) fails.
  4. Corrected: In step 2, there are (always) no message window.
  5. Corrected: In step 3, there are (always) a message window shows: “No synchronization info at this position”.

Expected behavior

  1. Forward sync should navigate to the corresponding position in SumatraPDF, and highlight the focused place in purple.
  2. Backward sync should open and jump to the relevant line in the source file (VS Code).

File that reproduces the problem

No. Path Synch?
1 basic\testENG can
2 basic\testCN can
3 Test1 space\testENG1 can
4 Test1 space\testCN1 can
5 Test2 中文\testENG2 CANNOT (NEITHER forward and backward)
6 Test2 中文\testCN2 CANNOT (NEITHER forward and backward)
7 add1\test中文 CANNOT (NEITHER forward and backward)

Content from the unzipped testCN1.synctex file:

SyncTeX Version:1
Input:1:d:/Projects/A2_LATEX_Projects/D2_InverseSearch_issue/Test1 space/./testCN1.tex
Input:2:d:/ENV/texlive/2026/texmf-dist/tex/latex/ctex/ctexart.cls
Input:3:d:/ENV/texlive/2026/texmf-dist/tex/latex/ctex/config/ctexbackend.cfg
...

Content from the unzipped testCN2.synctex file:

SyncTeX Version:1
Input:1:d:/Projects/A2_LATEX_Projects/D2_InverseSearch_issue/Test2 中文/./testCN2.tex
Input:2:d:/ENV/texlive/2026/texmf-dist/tex/latex/ctex/ctexart.cls
Input:3:d:/ENV/texlive/2026/texmf-dist/tex/latex/ctex/config/ctexbackend.cfg
...

Discussion

  • Comparing No. 1 and No. 3: spaces in the path do not affect synchronization.
  • Comparing No. 3, No.5 and No. 7: non-ASCII characters (in direction name OR in file name) in the path will cause synchronization to fail.
  • Comparing testCN1.synctex and testCN2.synctex: /. s in .synctex file do not affect synchronization.

Directory structure

D:\Projects\A2_LATEX_Projects\D2_InverseSearch_issue\
├─add1
│      test中文.aux
│      test中文.fdb_latexmk
│      test中文.fls
│      test中文.log
│      test中文.pdf
│      test中文.synctex.gz
│      test中文.tex
│      test中文.xdv
│      
├─basic
│      testCN.aux
│      testCN.fdb_latexmk
│      testCN.fls
│      testCN.log
│      testCN.pdf
│      testCN.synctex.gz
│      testCN.tex
│      testCN.xdv
│      testENG.aux
│      testENG.fdb_latexmk
│      testENG.fls
│      testENG.log
│      testENG.pdf
│      testENG.synctex.gz
│      testENG.tex
│      testENG.xdv
│
├─Test1 space
│      testCN1.aux
│      testCN1.fdb_latexmk
│      testCN1.fls
│      testCN1.log
│      testCN1.pdf
│      testCN1.synctex.gz
│      testCN1.tex
│      testCN1.xdv
│      testENG1.aux
│      testENG1.fdb_latexmk
│      testENG1.fls
│      testENG1.log
│      testENG1.pdf
│      testENG1.synctex.gz
│      testENG1.tex
│      testENG1.xdv
│
└─Test2 中文
        testCN2.aux
        testCN2.fdb_latexmk
        testCN2.fls
        testCN2.log
        testCN2.pdf
        testCN2.synctex.gz
        testCN2.tex
        testCN2.xdv
        testENG2.aux
        testENG2.fdb_latexmk
        testENG2.fls
        testENG2.log
        testENG2.pdf
        testENG2.synctex.gz
        testENG2.tex
        testENG2.xdv

Screenshots
testENG1 (No3), forward:

Image

testENG2 (No5), forward:

Image

testENG2 (No5), backward:

Image

Relative Code

  • Forward:

    // Show the result of a PDF forward-search synchronization (initiated by a DDE command)
    void ShowForwardSearchResult(MainWindow* win, const char* fileName, int line, int /* col */, int ret, int page,
    Vec<Rect>& rects) {
    ReportIf(!win->AsFixed());
    DisplayModel* dm = win->AsFixed();
    win->fwdSearchMark.rects.Reset();
    const PageInfo* pi = dm->GetPageInfo(page);
    if ((ret == PDFSYNCERR_SUCCESS) && (rects.size() > 0) && (nullptr != pi)) {
    // remember the position of the search result for drawing the rect later on
    win->fwdSearchMark.rects = rects;
    win->fwdSearchMark.page = page;
    win->fwdSearchMark.show = true;
    win->fwdSearchMark.hideStep = 0;
    if (!gGlobalPrefs->forwardSearch.highlightPermanent) {
    SetTimer(win->hwndCanvas, HIDE_FWDSRCHMARK_TIMER_ID, HIDE_FWDSRCHMARK_DELAY_IN_MS, nullptr);
    }
    // Scroll to show the overall highlighted zone
    int pageNo = page;
    Rect overallrc = rects.at(0);
    for (size_t i = 1; i < rects.size(); i++) {
    overallrc = overallrc.Union(rects.at(i));
    }
    TextSel res = {1, 1, &pageNo, &overallrc};
    if (!dm->PageVisible(page)) {
    win->ctrl->GoToPage(page, true);
    }
    if (!dm->ShowResultRectToScreen(&res)) {
    ScheduleRepaint(win, 0);
    }
    if (IsIconic(win->hwndFrame)) {
    ShowWindowAsync(win->hwndFrame, SW_RESTORE);
    }
    return;
    }
    TempStr buf = nullptr;
    NotificationCreateArgs args{};
    args.hwndParent = win->hwndCanvas;
    if (ret == PDFSYNCERR_SYNCFILE_NOTFOUND) {
    args.msg = _TRA("No synchronization file found");
    } else if (ret == PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED) {
    args.msg = _TRA("Synchronization file cannot be opened");
    } else if (ret == PDFSYNCERR_INVALID_PAGE_NUMBER) {
    buf = str::FormatTemp(_TRA("Page number %u inexistant"), page);
    } else if (ret == PDFSYNCERR_NO_SYNC_AT_LOCATION) {
    args.msg = _TRA("No synchronization info at this position");
    } else if (ret == PDFSYNCERR_UNKNOWN_SOURCEFILE) {
    buf = str::FormatTemp(_TRA("Unknown source file (%s)"), fileName);
    } else if (ret == PDFSYNCERR_NORECORD_IN_SOURCEFILE) {
    buf = str::FormatTemp(_TRA("Source file %s has no synchronization point"), fileName);
    } else if (ret == PDFSYNCERR_NORECORD_FOR_THATLINE) {
    buf = str::FormatTemp(_TRA("No result found around line %u in file %s"), line, fileName);
    } else if (ret == PDFSYNCERR_NOSYNCPOINT_FOR_LINERECORD) {
    buf = str::FormatTemp(_TRA("No result found around line %u in file %s"), line, fileName);
    }
    if (buf) {
    args.msg = buf;
    ShowNotification(args);
    }
    }

  • Backward:

    // returns true if inverse search was performed
    bool OnInverseSearch(MainWindow* win, int x, int y) {
    if (!CanAccessDisk() || gPluginMode) {
    return false;
    }
    WindowTab* tab = win->CurrentTab();
    if (!tab || tab->GetEngineType() != kindEngineMupdf) {
    return false;
    }
    DisplayModel* dm = tab->AsFixed();
    // Clear the last forward-search result
    win->fwdSearchMark.rects.Reset();
    InvalidateRect(win->hwndCanvas, nullptr, FALSE);
    // On double-clicking error message will be shown to the user
    // if the PDF does not have a synchronization file
    if (!dm->pdfSync) {
    const char* path = tab->filePath;
    int err = Synchronizer::Create(path, dm->GetEngine(), &dm->pdfSync);
    if (err == PDFSYNCERR_SYNCFILE_NOTFOUND) {
    // We used to warn that "No synchronization file found" at this
    // point if gGlobalPrefs->enableTeXEnhancements is set; we no longer
    // so do because a double-click has several other meanings
    // (selecting a word or an image, navigating quickly using links)
    // and showing an unrelated warning in all those cases seems wrong
    return false;
    }
    if (err != PDFSYNCERR_SUCCESS) {
    NotificationCreateArgs args;
    args.hwndParent = win->hwndCanvas;
    args.msg = _TRA("Synchronization file cannot be opened");
    ShowNotification(args);
    return true;
    }
    gGlobalPrefs->enableTeXEnhancements = true;
    }
    int pageNo = dm->GetPageNoByPoint(Point(x, y));
    if (!tab->ctrl->ValidPageNo(pageNo)) {
    return false;
    }
    Point pt = ToPoint(dm->CvtFromScreen(Point(x, y), pageNo));
    AutoFreeStr srcfilepath;
    int line = 0;
    int col = 0;
    int err = dm->pdfSync->DocToSource(pageNo, pt, srcfilepath, &line, &col);
    if (err != PDFSYNCERR_SUCCESS) {
    NotificationCreateArgs args;
    args.hwndParent = win->hwndCanvas;
    args.msg = _TRA("No synchronization info at this position");
    ShowNotification(args);
    return true;
    }
    if (!file::Exists(srcfilepath)) {
    // if the source file is missing, check if it's been moved to the same place as
    // the PDF document (which happens if all files are moved together)
    TempStr altsrcpath = path::GetDirTemp(tab->filePath);
    altsrcpath = path::JoinTemp(altsrcpath, path::GetBaseNameTemp(srcfilepath));
    if (!str::Eq(altsrcpath, srcfilepath) && file::Exists(altsrcpath)) {
    srcfilepath.SetCopy(altsrcpath);
    }
    }
    char* inverseSearch = gGlobalPrefs->inverseSearchCmdLine;
    if (!inverseSearch) {
    Vec<TextEditor*> editors;
    DetectTextEditors(editors);
    if (editors.Size() > 0) {
    inverseSearch = str::DupTemp(editors[0]->openFileCmd);
    }
    }
    AutoFreeStr cmdLine;
    if (inverseSearch) {
    cmdLine = BuildOpenFileCmd(inverseSearch, srcfilepath, line, col);
    }
    NotificationCreateArgs args;
    args.hwndParent = win->hwndCanvas;
    args.msg = _TRA("Cannot start inverse search command. Please check the command line in the settings.");
    if (!str::IsEmpty(cmdLine.Get())) {
    // resolve relative paths with relation to SumatraPDF.exe's directory
    char* appDir = GetSelfExeDirTemp();
    AutoCloseHandle process(LaunchProcessInDir(cmdLine, appDir));
    if (!process) {
    ShowNotification(args);
    }
    } else if (gGlobalPrefs->enableTeXEnhancements) {
    ShowNotification(args);
    }
    return true;
    }

Additional context
I suggest making the info messages more distinguishable between forward and backward sync failures for better debugging.
E.g. "[source to PDF] No synchronization info at this position" and "[PDF to source] No synchronization info at this position"

Test files
D2_InverseSearch_issue.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions