diff --git a/src/LineData.h b/src/LineData.h index 871c4f47..602da4fd 100644 --- a/src/LineData.h +++ b/src/LineData.h @@ -23,6 +23,7 @@ struct LineDataLine { DWORD number; + DWORD column; std::wstring text; }; diff --git a/src/Resources/grepWin.rc b/src/Resources/grepWin.rc index 90fd7af7..1b6d896d 100644 --- a/src/Resources/grepWin.rc +++ b/src/Resources/grepWin.rc @@ -191,10 +191,10 @@ CAPTION "grepWin Settings" FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN GROUPBOX "Editor",IDC_EDITORGROUP,7,7,303,61 - LTEXT "Command line to start an editor at a specific line:",IDC_STATIC1,13,19,288,8 + LTEXT "Command line to start an editor at a specific line and in line offset:",IDC_STATIC1,13,19,288,8 EDITTEXT IDC_EDITORCMD,13,31,269,14,ES_AUTOHSCROLL PUSHBUTTON "...",IDC_SEARCHPATHBROWSE,286,31,15,14 - LTEXT "%path% is replaced with the path of the file, %line% with the line to jump to",IDC_STATIC2,13,47,288,17 + LTEXT "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset",IDC_STATIC2,13,47,288,17 LTEXT "Language:",IDC_STATIC4,7,72,135,8 COMBOBOX IDC_LANGUAGE,170,71,140,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "number of NULL bytes per MB allowed for a file to still be considered text instead of binary",IDC_STATIC3,7,85,241,17 @@ -376,6 +376,7 @@ BEGIN IDS_REGEXINVALID "invalid regex!" IDS_SIZE "Size" IDS_LINE "Line" + IDS_COLUMN "Column" IDS_MATCHES "Matches" IDS_TEXT "Text" IDS_PATH "Path" @@ -395,7 +396,7 @@ BEGIN IDS_COPYRESULT "Copy text result to clipboard" IDS_COPYRESULTS "Copy text results to clipboard" IDS_XMOREMATCHES "%ld more matches" - IDS_CONTEXTLINE "Line %5ld : %30s\n" + IDS_CONTEXTLINE "Line %5ld : %s\n" IDS_INFOLABELFILE "scanning file '%s'" IDS_ERR_RELATIVEPATH "Relative paths are not allowed. Please enter an absolute path!" IDS_ERR_INVALID_PATH "Invalid path!" diff --git a/src/SearchDlg.cpp b/src/SearchDlg.cpp index c208fb19..844f84a6 100644 --- a/src/SearchDlg.cpp +++ b/src/SearchDlg.cpp @@ -78,7 +78,6 @@ DWORD WINAPI SearchThreadEntry(LPVOID lpParam); // ReSharper disable once CppInconsistentNaming UINT CSearchDlg::m_grepwinStartupmsg = RegisterWindowMessage(L"grepWin_StartupMessage"); -std::map linePositions; extern ULONGLONG g_startTime; extern HANDLE hInitProtection; @@ -810,8 +809,14 @@ LRESULT CSearchDlg::DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPara switch (wParam) { case IDC_RESULTLIST: + { + if (reinterpret_cast(lParam)->code == NM_CUSTOMDRAW) + { + return ColorizeMatchResultProc((LPNMLVCUSTOMDRAW)lParam); + } DoListNotify(reinterpret_cast(lParam)); break; + } case IDOK: switch (reinterpret_cast(lParam)->code) { @@ -1983,6 +1988,7 @@ bool CSearchDlg::InitResultList() std::wstring sName = TranslatedString(hResource, IDS_NAME); std::wstring sSize = TranslatedString(hResource, IDS_SIZE); std::wstring sLine = TranslatedString(hResource, IDS_LINE); + std::wstring sMove = TranslatedString(hResource, IDS_COLUMN); std::wstring sMatches = TranslatedString(hResource, IDS_MATCHES); std::wstring sText = TranslatedString(hResource, IDS_TEXT); std::wstring sPath = TranslatedString(hResource, IDS_PATH); @@ -1996,16 +2002,16 @@ bool CSearchDlg::InitResultList() lvc.cx = -1; lvc.pszText = const_cast(static_cast(sName.c_str())); ListView_InsertColumn(hListControl, 0, &lvc); - lvc.pszText = filelist ? const_cast(static_cast(sSize.c_str())) : const_cast(static_cast(sLine.c_str())); - lvc.fmt = filelist ? LVCFMT_RIGHT : LVCFMT_LEFT; - ListView_InsertColumn(hListControl, 1, &lvc); - lvc.fmt = LVCFMT_LEFT; - lvc.pszText = filelist ? const_cast(static_cast(sMatches.c_str())) : const_cast(static_cast(sText.c_str())); - ListView_InsertColumn(hListControl, 2, &lvc); - lvc.pszText = const_cast(static_cast(sPath.c_str())); - ListView_InsertColumn(hListControl, 3, &lvc); if (filelist) { + lvc.fmt = LVCFMT_RIGHT; + lvc.pszText = const_cast(static_cast(sSize.c_str())); + ListView_InsertColumn(hListControl, 1, &lvc); + lvc.fmt = LVCFMT_LEFT; + lvc.pszText = const_cast(static_cast(sMatches.c_str())); + ListView_InsertColumn(hListControl, 2, &lvc); + lvc.pszText = const_cast(static_cast(sPath.c_str())); + ListView_InsertColumn(hListControl, 3, &lvc); lvc.pszText = const_cast(static_cast(sExtension.c_str())); ListView_InsertColumn(hListControl, 4, &lvc); lvc.pszText = const_cast(static_cast(sEncoding.c_str())); @@ -2013,6 +2019,17 @@ bool CSearchDlg::InitResultList() lvc.pszText = const_cast(static_cast(sDateModified.c_str())); ListView_InsertColumn(hListControl, 6, &lvc); } + else + { + lvc.pszText = const_cast(static_cast(sLine.c_str())); + ListView_InsertColumn(hListControl, 1, &lvc); + lvc.pszText = const_cast(static_cast(sMove.c_str())); + ListView_InsertColumn(hListControl, 2, &lvc); + lvc.pszText = const_cast(static_cast(sText.c_str())); + ListView_InsertColumn(hListControl, 3, &lvc); + lvc.pszText = const_cast(static_cast(sPath.c_str())); + ListView_InsertColumn(hListControl, 4, &lvc); + } ListView_SetColumnWidth(hListControl, 0, 300); ListView_SetColumnWidth(hListControl, 1, 50); @@ -2260,7 +2277,10 @@ void CSearchDlg::ShowContextMenu(HWND hWnd, int x, int y) data.path = info.filePath; LineDataLine dataLine; if (static_cast(info.matchLinesNumbers.size()) > subIdx) + { dataLine.number = info.matchLinesNumbers[subIdx]; + dataLine.column = info.matchColumnsNumbers[subIdx]; + } if (static_cast(info.matchLines.size()) > subIdx) dataLine.text = info.matchLines[subIdx]; data.lines.push_back(dataLine); @@ -2423,6 +2443,107 @@ bool CSearchDlg::PreTranslateMessage(MSG* pMsg) return false; } +LRESULT CSearchDlg::ColorizeMatchResultProc(LPNMLVCUSTOMDRAW lpLVCD) +{ + switch (lpLVCD->nmcd.dwDrawStage) + { + case CDDS_PREPAINT: // theme hooks this stage + return CDRF_NOTIFYITEMDRAW; + case CDDS_ITEMPREPAINT: + return CDRF_NOTIFYSUBITEMDRAW; + case CDDS_ITEMPREPAINT | CDDS_SUBITEM: + return CDRF_NOTIFYPOSTPAINT | CDRF_NEWFONT; + case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM: // use the theme color + { + if (lpLVCD->iSubItem == 3 && IsDlgButtonChecked(*this, IDC_RESULTFILES) != BST_CHECKED) + { + HDC hdc = lpLVCD->nmcd.hdc; + RECT rc = lpLVCD->nmcd.rc; // lpLVCD->rcText does not work + if (rc.top == 0) + { + // hover on items + break; + } + + int iRow = (int)(lpLVCD->nmcd.dwItemSpec); + auto tup = m_listItems[iRow]; + int index = std::get<0>(tup); + CSearchInfo* pInfo = &m_items[index]; + if (pInfo->encoding == CTextFile::Binary) + { + break; + } + + int subIndex = std::get<1>(tup); + int lenText = static_cast(pInfo->matchLines[subIndex].length()); + + auto colMatch = pInfo->matchColumnsNumbers[subIndex]; + WCHAR textBuf[MAX_PATH] = {0}; + if (colMatch + pInfo->matchLengths[subIndex] >= MAX_PATH) + { + // LV_ITEM: Allows any length string to be stored as item text, only the first 259 TCHARs are displayed. + // 259, I counted it, not 260. + break; + } + + HWND hListControl = GetDlgItem(*this, IDC_RESULTLIST); + LVITEM lv = {0}; + lv.iItem = iRow; + lv.iSubItem = 3; + lv.mask = LVIF_TEXT; + lv.pszText = textBuf; + if (lenText + 1 > _countof(textBuf)) + { + lv.cchTextMax = _countof(textBuf); + } + else + { + lv.cchTextMax = lenText + 1; + } + if (ListView_GetItem(hListControl, &lv)) + { + LPWSTR pMatch = lv.pszText + colMatch - 1; + SIZE textSize = {0, 0}; + + rc.left += 6; + rc.right -= 6; + + // Not precise sometimes. + // We keep the text and draw a transparent rectangle only. So, will not break the text. + GetTextExtentPoint32(hdc, lv.pszText, colMatch - 1, &textSize); + rc.left += textSize.cx; + if (rc.left >= rc.right) + { + break; + } + GetTextExtentPoint32(hdc, pMatch, pInfo->matchLengths[subIndex], &textSize); + if (rc.right > rc.left + textSize.cx) + { + rc.right = rc.left + textSize.cx; + } + + LONG width = rc.right - rc.left; + LONG height = rc.bottom - rc.top; + HDC hcdc = CreateCompatibleDC(hdc); + BITMAPINFO bmi = { {sizeof(BITMAPINFOHEADER), width, height, 1, 32, BI_RGB, width * height * 4u, 0, 0, 0, 0}, {{0, 0, 0, 0}} }; + BLENDFUNCTION blend = {AC_SRC_OVER, 0, 92, 0}; // 36% + HBITMAP hBitmap = CreateDIBSection(hcdc, &bmi, DIB_RGB_COLORS, NULL, NULL, 0x0); + RECT rc2 = {0, 0, width, height}; + SelectObject(hcdc, hBitmap); + FillRect(hcdc, &rc2, CreateSolidBrush(RGB(255, 255, 0))); + AlphaBlend(hdc, rc.left, rc.top, width, height, hcdc, 0, 0, width, height, blend); + DeleteObject(hBitmap); + DeleteDC(hcdc); + } + } + } + default: + break; + } + + return CDRF_DODEFAULT; +} + void CSearchDlg::DoListNotify(LPNMITEMACTIVATE lpNMItemActivate) { if (lpNMItemActivate->hdr.code == NM_DBLCLK) @@ -2509,11 +2630,14 @@ void CSearchDlg::DoListNotify(LPNMITEMACTIVATE lpNMItemActivate) } break; case 3: - if (m_bAscending) - std::ranges::sort(m_items, CSearchInfo::PathCompareAsc); - else - std::ranges::sort(m_items, CSearchInfo::PathCompareDesc); - bDidSort = true; + if (fileList) + { + if (m_bAscending) + std::ranges::sort(m_items, CSearchInfo::PathCompareAsc); + else + std::ranges::sort(m_items, CSearchInfo::PathCompareDesc); + bDidSort = true; + } break; case 4: if (m_bAscending) @@ -2585,37 +2709,51 @@ void CSearchDlg::DoListNotify(LPNMITEMACTIVATE lpNMItemActivate) } else if (lpNMItemActivate->hdr.code == LVN_GETINFOTIP) { - NMLVGETINFOTIP* pInfoTip = reinterpret_cast(lpNMItemActivate); + NMLVGETINFOTIP* pInfoTip = reinterpret_cast(lpNMItemActivate); + + size_t listIndex = pInfoTip->iItem; + auto tup = m_listItems[listIndex]; + int iItem = std::get<0>(tup); + CSearchInfo& inf = m_items[iItem]; + int subIndex = 0; - // Which item number? - size_t itemId = pInfoTip->iItem; - int iItem = GetSelectedListIndex(static_cast(itemId)); - pInfoTip->pszText[0] = 0; - if (static_cast(m_items.size()) > iItem) + bool fileList = (IsDlgButtonChecked(*this, IDC_RESULTFILES) == BST_CHECKED); + + if (!fileList) { - CSearchInfo inf = m_items[iItem]; + subIndex = std::get<1>(tup); + } - std::wstring matchString = inf.filePath + L"\n"; - if (!inf.exception.empty()) - { - matchString += inf.exception; - matchString += L"\n"; - } - std::wstring sFormat = TranslatedString(hResource, IDS_CONTEXTLINE); - for (size_t i = 0; i < min(inf.matchLines.size(), 5); ++i) - { - std::wstring matchText = inf.matchLines[i]; - CStringUtils::trim(matchText); - matchString += CStringUtils::Format(sFormat.c_str(), inf.matchLinesNumbers[i], matchText.c_str()); - } - if (inf.matchLines.size() > 5) + std::wstring matchString = inf.filePath + L"\n"; + if (!inf.exception.empty()) + { + matchString += inf.exception; + matchString += L"\n"; + } + + std::wstring sFormat = TranslatedString(hResource, IDS_CONTEXTLINE); + int leftMax = static_cast(inf.matchLines.size()); + int showMax = min(leftMax, subIndex + 5); + for (; subIndex < showMax; ++subIndex) + { + std::wstring matchText = inf.matchLines[subIndex]; + CStringUtils::rtrim(matchText); + DWORD iShow = 0; + if (inf.matchColumnsNumbers[subIndex] > 8) { - std::wstring sx = TranslatedString(hResource, IDS_XMOREMATCHES); - std::wstring ssx = CStringUtils::Format(sx.c_str(), static_cast(inf.matchLines.size() - 5)); - matchString += ssx; + // 6 + 1 prefix chars would give a context + iShow = inf.matchColumnsNumbers[subIndex] - 8; } - wcsncpy_s(pInfoTip->pszText, pInfoTip->cchTextMax, matchString.c_str(), pInfoTip->cchTextMax - 1LL); + matchString += CStringUtils::Format(sFormat.c_str(), inf.matchLinesNumbers[subIndex], matchText.substr(iShow, 50).c_str()); + } + leftMax -= subIndex; + if (leftMax > 0) + { + std::wstring sx = TranslatedString(hResource, IDS_XMOREMATCHES); + std::wstring ssx = CStringUtils::Format(sx.c_str(), leftMax); + matchString += ssx; } + wcsncpy_s(pInfoTip->pszText, pInfoTip->cchTextMax, matchString.c_str(), pInfoTip->cchTextMax - 1LL); } else if (lpNMItemActivate->hdr.code == LVN_GETDISPINFO) { @@ -2720,7 +2858,7 @@ void CSearchDlg::DoListNotify(LPNMITEMACTIVATE lpNMItemActivate) case 1: // binary wcsncpy_s(pItem->pszText, pItem->cchTextMax, sBinary.c_str(), pItem->cchTextMax); break; - case 3: // path + case 4: // path wcsncpy_s(pItem->pszText, pItem->cchTextMax, pInfo->filePath.substr(0, pInfo->filePath.size() - pInfo->filePath.substr(pInfo->filePath.find_last_of('\\') + 1).size() - 1).c_str(), pItem->cchTextMax - 1LL); break; default: @@ -2745,7 +2883,10 @@ void CSearchDlg::DoListNotify(LPNMITEMACTIVATE lpNMItemActivate) case 1: // line number swprintf_s(pItem->pszText, pItem->cchTextMax, L"%ld", pInfo->matchLinesNumbers[subIndex]); break; - case 2: // line + case 2: // move number + swprintf_s(pItem->pszText, pItem->cchTextMax, L"%ld", pInfo->matchColumnsNumbers[subIndex]); + break; + case 3: // line { std::wstring line; if (pInfo->matchLines.size() > static_cast(subIndex)) @@ -2756,7 +2897,7 @@ void CSearchDlg::DoListNotify(LPNMITEMACTIVATE lpNMItemActivate) wcsncpy_s(pItem->pszText, pItem->cchTextMax, line.c_str(), pItem->cchTextMax - 1LL); } break; - case 3: // path + case 4: // path wcsncpy_s(pItem->pszText, pItem->cchTextMax, pInfo->filePath.substr(0, pInfo->filePath.size() - pInfo->filePath.substr(pInfo->filePath.find_last_of('\\') + 1).size() - 1).c_str(), pItem->cchTextMax - 1LL); break; default: @@ -2774,14 +2915,34 @@ void CSearchDlg::DoListNotify(LPNMITEMACTIVATE lpNMItemActivate) } } +void static OpenFileInProcess(LPWSTR lpCommandLine) +{ + STARTUPINFO startupInfo{}; + PROCESS_INFORMATION processInfo{}; + startupInfo.cb = sizeof(STARTUPINFO); + CreateProcess(nullptr, lpCommandLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startupInfo, &processInfo); + CloseHandle(processInfo.hThread); + CloseHandle(processInfo.hProcess); +} + void CSearchDlg::OpenFileAtListIndex(int listIndex) { - int iItem = GetSelectedListIndex(listIndex); - CSearchInfo inf = m_items[iItem]; - size_t dotPos = inf.filePath.rfind('.'); - std::wstring ext; - if (dotPos != std::wstring::npos) - ext = inf.filePath.substr(dotPos); + auto tup = m_listItems[listIndex]; + int iItem = std::get<0>(tup); + CSearchInfo& inf = m_items[iItem]; + auto subIndex = 0; + wchar_t line[32]; + wchar_t move[32]; + + bool fileList = (IsDlgButtonChecked(*this, IDC_RESULTFILES) == BST_CHECKED); + + if (!fileList) + { + subIndex = std::get<1>(tup); + } + + swprintf_s(line, 32, L"%ld", inf.matchLinesNumbers[subIndex]); + swprintf_s(move, 32, L"%ld", inf.matchColumnsNumbers[subIndex]); CRegStdString regEditorCmd(L"Software\\grepWin\\editorcmd"); std::wstring cmd = regEditorCmd; @@ -2789,44 +2950,18 @@ void CSearchDlg::OpenFileAtListIndex(int listIndex) cmd = g_iniFile.GetValue(L"global", L"editorcmd", L""); if (!cmd.empty() && !inf.readError && inf.encoding != CTextFile::UnicodeType::Binary) { - bool fileList = (IsDlgButtonChecked(*this, IDC_RESULTFILES) == BST_CHECKED); - if (!fileList) - { - HWND hListControl = GetDlgItem(*this, IDC_RESULTLIST); - wchar_t textLineBuf[MAX_PATH] = {0}; - LVITEM lv = {0}; - lv.iItem = listIndex; - lv.iSubItem = 1; // line number - lv.mask = LVIF_TEXT; - lv.pszText = textLineBuf; - lv.cchTextMax = _countof(textLineBuf); - if (ListView_GetItem(hListControl, &lv)) - { - if (_wtol(textLineBuf) == 0) - wcscpy_s(textLineBuf, L"0"); - SearchReplace(cmd, L"%line%", textLineBuf); - } - } - else - { - // use the first matching line in this file - if (!inf.matchLinesNumbers.empty()) - SearchReplace(cmd, L"%line%", CStringUtils::Format(L"%lu", inf.matchLinesNumbers[0])); - else - SearchReplace(cmd, L"%line%", L"0"); - } - - SearchReplace(cmd, L"%path%", inf.filePath.c_str()); - - STARTUPINFO startupInfo{}; - PROCESS_INFORMATION processInfo{}; - startupInfo.cb = sizeof(STARTUPINFO); - CreateProcess(nullptr, const_cast(cmd.c_str()), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startupInfo, &processInfo); - CloseHandle(processInfo.hThread); - CloseHandle(processInfo.hProcess); + SearchReplace(cmd, L"%line%", line); + SearchReplace(cmd, L"%column%", move); + SearchReplace(cmd, L"%path%", inf.filePath); + OpenFileInProcess(const_cast(cmd.c_str())); return; } + size_t dotPos = inf.filePath.rfind('.'); + std::wstring ext; + if (dotPos != std::wstring::npos) + ext = inf.filePath.substr(dotPos); + DWORD bufLen = 0; if (AssocQueryString(ASSOCF_INIT_DEFAULTTOSTAR, ASSOCSTR_DDECOMMAND, ext.c_str(), nullptr, nullptr, &bufLen) == S_OK) { @@ -2838,6 +2973,7 @@ void CSearchDlg::OpenFileAtListIndex(int listIndex) return; } } + bufLen = 0; AssocQueryString(ASSOCF_INIT_DEFAULTTOSTAR, ASSOCSTR_COMMAND, ext.c_str(), nullptr, nullptr, &bufLen); auto cmdBuf = std::make_unique(bufLen + 1LL); @@ -2850,119 +2986,111 @@ void CSearchDlg::OpenFileAtListIndex(int listIndex) application = cmdBuf.get(); // resolve parameters - if (application.find(L"%1") == std::wstring::npos) + std::wstring appname = application; + std::ranges::transform(appname, appname.begin(), ::towlower); + std::wstring quote = L"\""; + std::wstring params; + std::wstring paramsSuffix; + bool bDontQuotePath = FALSE; + + std::wstring argHolder = L"%1"; + size_t holderIndex = application.find(argHolder); + size_t reservedLength; + if (holderIndex == std::wstring::npos) + { + reservedLength = application.length() + 1; application += L" %1"; - - bool fileList = (IsDlgButtonChecked(*this, IDC_RESULTFILES) == BST_CHECKED); - std::wstring lineNumberParamBefore; - std::wstring lineNumberParam; - wchar_t textLineBuf[MAX_PATH] = {0}; - if (!fileList) + } + else { - HWND hListControl = GetDlgItem(*this, IDC_RESULTLIST); - LVITEM lv = {0}; - lv.iItem = listIndex; - lv.iSubItem = 1; // line number - lv.mask = LVIF_TEXT; - lv.pszText = textLineBuf; - lv.cchTextMax = _countof(textLineBuf); - if (!ListView_GetItem(hListControl, &lv)) + reservedLength = holderIndex; + if (holderIndex > 0 && application[holderIndex - 1] == L'"') { - textLineBuf[0] = '\0'; + reservedLength--; + // replace "%1" with %1 + SearchReplace(application, L"\"%1\"", argHolder); } } - else if (!inf.matchLinesNumbers.empty()) - { - // use the first matching line in this file - swprintf_s(textLineBuf, L"%ld", inf.matchLinesNumbers[0]); - } - if (textLineBuf[0] == 0) - wcscpy_s(textLineBuf, L"0"); - std::wstring appname = application; - std::ranges::transform(appname, appname.begin(), ::towlower); // now find out if the application which opens the file is known to us - // and if it has a 'linenumber' switch to jump directly to a specific - // line number. + // and add extra params to the "%1" for better locating. if (appname.find(L"notepad++.exe") != std::wstring::npos) { - // notepad++ - lineNumberParam = CStringUtils::Format(L"-n%s", textLineBuf); + params = CStringUtils::Format(L"-n%s -c%s ", line, move); } else if (appname.find(L"xemacs.exe") != std::wstring::npos) { - // XEmacs - lineNumberParam = CStringUtils::Format(L"+%s", textLineBuf); - } - else if (appname.find(L"uedit32.exe") != std::wstring::npos) - { - // UltraEdit - lineNumberParam = CStringUtils::Format(L"-l%s", textLineBuf); + params = CStringUtils::Format(L"+%s ", line); } - else if (appname.find(L"codewright.exe") != std::wstring::npos) + else if ((appname.find(L"uedit32.exe") != std::wstring::npos) || (appname.find(L"uedit64.exe") != std::wstring::npos)) { - // CodeWright - lineNumberParam = CStringUtils::Format(L"-G%s", textLineBuf); + // UltraEdit, `//` covers more (old) versions than `-l -c` + params = quote; + paramsSuffix = CStringUtils::Format(L"/%s/%s\"", line, move); + bDontQuotePath = TRUE; } else if (appname.find(L"notepad2.exe") != std::wstring::npos) { - // Notepad2 - auto escapedSearch = m_searchString; - SearchReplace(escapedSearch, L"\"", L"\\\""); - lineNumberParamBefore = CStringUtils::Format(L"/g %s /mr \"%s\"", textLineBuf, escapedSearch.c_str()); + std::wstring match; + if (inf.matchLines.size() > 0) + { + // not binary + const wchar_t* specialChar[17] = { + // oringinal + L"\\", + // regex special chars, current and future + L"^", L"$", L".", L"?", L"*", L"+", L"[", L"]", L"(", L")", L"{", L"}", L"|", + // command line special chars + L"\"", L" ", L"\t" + }; + const wchar_t* specialEscaped[17] = { + L"\\x5c", + L"\\^", L"\\$", L"\\.", L"\\?", L"\\*", L"\\+", L"\\[", L"\\]", L"\\(", L"\\)", L"\\{", L"\\}", L"\\|", + L"\\x22", L"\\x20", L"\\x09" + }; + match = inf.matchLines[subIndex].substr(inf.matchColumnsNumbers[subIndex] - 1, inf.matchLengths[subIndex]); + for (int i = 0; i < _countof(specialChar); ++i) + { + SearchReplace(match, specialChar[i], specialEscaped[i]); + } + if (match.length() > 32767 - 1 - 2 - 2 - 13 - inf.filePath.length() - reservedLength) + { + match.clear(); + } + } + params = CStringUtils::Format(L"/g %s,%s /mr \"%s\" ", line, move, match.c_str()); } else if ((appname.find(L"bowpad.exe") != std::wstring::npos) || (appname.find(L"bowpad64.exe") != std::wstring::npos)) { - // BowPad - lineNumberParam = CStringUtils::Format(L"/line:%s", textLineBuf); + paramsSuffix = CStringUtils::Format(L" /line:%s", line); } else if (appname.find(L"code.exe") != std::wstring::npos) { // Visual Studio Code - lineNumberParamBefore = L"--goto"; - lineNumberParam = CStringUtils::Format(L":%s", textLineBuf); - } - - // replace "%1" with %1 - std::wstring tag = L"\"%1\""; - std::wstring repl = L"%1"; - std::wstring::iterator itBegin = search(application.begin(), application.end(), tag.begin(), tag.end()); - if (itBegin != application.end()) - { - std::wstring::iterator itEnd = itBegin + tag.size(); - application.replace(itBegin, itEnd, repl); + params = L"-g "; + paramsSuffix = CStringUtils::Format(L":%s:%s", line, move); } - // replace %1 with "path/of/selected/file" - tag = L"%1"; - if (application.find(L"rundll32.exe") == std::wstring::npos && application.find(L"--single-argument") == std::wstring::npos) - repl = L"\"" + inf.filePath + L"\""; - else - repl = inf.filePath; - if (!lineNumberParamBefore.empty()) + else if (application.find(L"-single-argument") != std::wstring::npos) { - repl = lineNumberParamBefore + L" " + repl; + // Chrome family: all following are path that does not need double quotes, even if there are spaces + // https://chromium.googlesource.com/chromium/src/+/refs/heads/main/base/command_line.cc + bDontQuotePath = TRUE; } - itBegin = std::ranges::search(application, tag).begin(); - if (itBegin != application.end()) + + if (bDontQuotePath) { - std::wstring::iterator itEnd = itBegin + tag.size(); - application.replace(itBegin, itEnd, repl); + params += inf.filePath; } - if (!lineNumberParam.empty()) + else { - if (!lineNumberParam.starts_with(L":")) - { - application += L" "; - } - application += lineNumberParam; + params += quote + inf.filePath + quote; } + params += paramsSuffix; - STARTUPINFO startupInfo{}; - PROCESS_INFORMATION processInfo{}; - startupInfo.cb = sizeof(STARTUPINFO); - CreateProcess(nullptr, const_cast(application.c_str()), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startupInfo, &processInfo); - CloseHandle(processInfo.hThread); - CloseHandle(processInfo.hProcess); + // replace %1 with the final decorated path + SearchReplace(application, argHolder, params); + + OpenFileInProcess(const_cast(application.c_str())); } bool grepWinIsRegexValid(const std::wstring& searchString) @@ -3707,6 +3835,30 @@ bool CSearchDlg::MatchPath(LPCTSTR pathBuf) const return bPattern; } +static long columnFromPosition(const std::wstring& textContent, long pos, long* lenLineEncodingPre) +{ + *lenLineEncodingPre = 0; + if (pos == 0) + { + return 1; + } + + long i = pos; + while (i > 0 && textContent[i] != L'\n' && textContent[i] != L'\r') + { + --i; + } + if (i >= 2 && textContent[i] == L'\n' && textContent[i - 1] == L'\r') + { + *lenLineEncodingPre = 2; + } + else if (i > 0) + { + *lenLineEncodingPre = 1; + } + return pos - i; +} + void CSearchDlg::SearchFile(CSearchInfo sInfo, const std::wstring& searchRoot, bool bSearchAlways, bool bIncludeBinary, bool bUseRegex, bool bCaseSensitive, bool bDotMatchesNewline, const std::wstring& searchString, const std::wstring& searchStringUtf16Le, std::atomic_bool& bCancelled) { int nFound = 0; @@ -3779,8 +3931,6 @@ void CSearchDlg::SearchFile(CSearchInfo sInfo, const std::wstring& searchRoot, b boost::match_flag_type flags = boost::match_default | boost::format_all; if (!bDotMatchesNewline) flags |= boost::match_not_dot_newline; - long prevLineStart = 0; - long prevLineEnd = 0; while (!bCancelled && regex_search(start, end, whatC, expression, flags)) { if (whatC[0].matched) @@ -3788,26 +3938,40 @@ void CSearchDlg::SearchFile(CSearchInfo sInfo, const std::wstring& searchRoot, b nFound++; if (m_bNotSearch) break; - long lineStart = textFile.LineFromPosition(static_cast(whatC[0].first - textFile.GetFileString().begin())); - long lineEnd = textFile.LineFromPosition(static_cast(whatC[0].second - textFile.GetFileString().begin())); - if ((lineStart != prevLineStart) || (lineEnd != prevLineEnd)) + long posMatch = static_cast(whatC[0].first - textFile.GetFileString().begin()); + long lineStart = textFile.LineFromPosition(posMatch); + long lineEnd = textFile.LineFromPosition(static_cast(whatC[0].second - textFile.GetFileString().begin())); + long lenLineEncodingPre = 0; + long colMatch = columnFromPosition(textFile.GetFileString(), posMatch, &lenLineEncodingPre); + long lenMatch = static_cast(whatC[0].length()); + for (long l = lineStart; l <= lineEnd; ++l) { - for (long l = lineStart; l <= lineEnd; ++l) + auto sLine = textFile.GetLineString(l); + long lenLineMatch = static_cast(sLine.length()) - colMatch; + if (lenMatch < lenLineMatch) { - auto sLine = textFile.GetLineString(l); - if (m_bCaptureSearch) - { - auto out = whatC.format(m_replaceString, flags); - sInfo.matchLines.push_back(std::move(out)); - } - else - sInfo.matchLines.push_back(std::move(sLine)); - sInfo.matchLinesNumbers.push_back(l); + lenLineMatch = lenMatch; + } + sInfo.matchLinesNumbers.push_back(l); + sInfo.matchColumnsNumbers.push_back(colMatch); + if (m_bCaptureSearch) + { + auto out = whatC.format(m_replaceString, flags); + sInfo.matchLines.push_back(std::move(out)); + sInfo.matchLengths.push_back(static_cast(out.length())); + } + else + { + sInfo.matchLines.push_back(std::move(sLine)); + sInfo.matchLengths.push_back(lenLineMatch); + } + if (lenMatch > lenLineMatch) + { + colMatch = 1; + lenMatch -= lenLineMatch + lenLineEncodingPre; } } ++sInfo.matchCount; - prevLineStart = lineStart; - prevLineEnd = lineEnd; } // update search position: if (start == whatC[0].second) @@ -3835,28 +3999,42 @@ void CSearchDlg::SearchFile(CSearchInfo sInfo, const std::wstring& searchRoot, b nFound++; if (m_bNotSearch) break; - long lineStart = textFile.LineFromPosition(static_cast(whatC[0].first - textFile.GetFileString().begin())); - long lineEnd = textFile.LineFromPosition(static_cast(whatC[0].second - textFile.GetFileString().begin())); + long posMatch = static_cast(whatC[0].first - textFile.GetFileString().begin()); + long lineStart = textFile.LineFromPosition(posMatch); + long lineEnd = textFile.LineFromPosition(static_cast(whatC[0].second - textFile.GetFileString().begin())); + long lenLineEncodingPre = 0; + long colMatch = columnFromPosition(textFile.GetFileString(), posMatch, &lenLineEncodingPre); + long lenMatch = static_cast(whatC[0].length()); if (m_bCaptureSearch) { auto out = whatC.format(m_replaceString, flags); sInfo.matchLines.push_back(out); sInfo.matchLinesNumbers.push_back(lineStart); + sInfo.matchColumnsNumbers.push_back(colMatch); + sInfo.matchLengths.push_back(static_cast(out.length())); } else { - if ((lineStart != prevLineStart) || (lineEnd != prevLineEnd)) + for (long l = lineStart; l <= lineEnd; ++l) { - for (long l = lineStart; l <= lineEnd; ++l) + auto sLine = textFile.GetLineString(l); + long lenLineMatch = static_cast(sLine.length()) - colMatch; + if (lenMatch < lenLineMatch) + { + lenLineMatch = lenMatch; + } + sInfo.matchLines.push_back(sLine); + sInfo.matchLinesNumbers.push_back(l); + sInfo.matchColumnsNumbers.push_back(colMatch); + sInfo.matchLengths.push_back(lenLineMatch); + if (lenMatch > lenLineMatch) { - sInfo.matchLines.push_back(textFile.GetLineString(l)); - sInfo.matchLinesNumbers.push_back(l); + colMatch = 1; + lenMatch -= lenLineMatch + lenLineEncodingPre; } } } ++sInfo.matchCount; - prevLineStart = lineStart; - prevLineEnd = lineEnd; } // update search position: if (start == whatC[0].second) @@ -4018,6 +4196,7 @@ void CSearchDlg::SearchFile(CSearchInfo sInfo, const std::wstring& searchRoot, b { boost::regex expression = boost::regex(searchFor, ft); std::vector matchLinesNumbers; + std::vector matchColumnsNumbers; bool bFound = false; { boost::spirit::classic::file_iterator<> start(filePath.c_str()); @@ -4030,6 +4209,7 @@ void CSearchDlg::SearchFile(CSearchInfo sInfo, const std::wstring& searchRoot, b if (m_bNotSearch) break; matchLinesNumbers.push_back(static_cast(whatC[0].first - fBeg)); + matchColumnsNumbers.push_back(1); ++sInfo.matchCount; // update search position: start = whatC[0].second; @@ -4054,6 +4234,7 @@ void CSearchDlg::SearchFile(CSearchInfo sInfo, const std::wstring& searchRoot, b if (m_bNotSearch) break; matchLinesNumbers.push_back(static_cast(whatC[0].first - fBeg)); + matchColumnsNumbers.push_back(1); ++sInfo.matchCount; // update search position: start = whatC[0].second; @@ -4070,7 +4251,6 @@ void CSearchDlg::SearchFile(CSearchInfo sInfo, const std::wstring& searchRoot, b { if (!bLoadResult && (type != CTextFile::Binary) && !m_bNotSearch) { - linePositions.clear(); // open the file and set up a vector of all lines CAutoFile hFile; int retryCounter = 0; @@ -4084,9 +4264,10 @@ void CSearchDlg::SearchFile(CSearchInfo sInfo, const std::wstring& searchRoot, b } while (!hFile && retryCounter < 5); if (hFile) { - auto fBuf = std::make_unique(4096); - DWORD bytesRead = 0; - size_t pos = 0; + std::map linePositions; + auto fBuf = std::make_unique(4096); + DWORD bytesRead = 0; + size_t pos = 0; while (ReadFile(hFile, fBuf.get(), 4096, &bytesRead, nullptr)) { if (bytesRead == 0) @@ -4133,6 +4314,7 @@ void CSearchDlg::SearchFile(CSearchInfo sInfo, const std::wstring& searchRoot, b } } sInfo.matchLinesNumbers = matchLinesNumbers; + sInfo.matchColumnsNumbers = matchColumnsNumbers; if (m_bReplace) { diff --git a/src/SearchDlg.h b/src/SearchDlg.h index 2a0f0d6a..9712b027 100644 --- a/src/SearchDlg.h +++ b/src/SearchDlg.h @@ -109,6 +109,7 @@ class CSearchDlg : public CDialog void FillResultList(); bool AddFoundEntry(CSearchInfo* pInfo, bool bOnlyListControl = false); void ShowContextMenu(HWND hWnd, int x, int y); + LRESULT ColorizeMatchResultProc(LPNMLVCUSTOMDRAW lpLVCD); void DoListNotify(LPNMITEMACTIVATE lpNMItemActivate); void OpenFileAtListIndex(int listIndex); void UpdateInfoLabel(); diff --git a/src/SearchInfo.h b/src/SearchInfo.h index 551440cc..72ff8aae 100644 --- a/src/SearchInfo.h +++ b/src/SearchInfo.h @@ -49,6 +49,8 @@ class CSearchInfo std::wstring filePath; __int64 fileSize; std::vector matchLinesNumbers; + std::vector matchColumnsNumbers; + std::vector matchLengths; std::vector matchLines; __int64 matchCount; CTextFile::UnicodeType encoding; diff --git a/src/ShellContextMenu.cpp b/src/ShellContextMenu.cpp index 763d4839..8d7b7731 100644 --- a/src/ShellContextMenu.cpp +++ b/src/ShellContextMenu.cpp @@ -342,6 +342,8 @@ UINT CShellContextMenu::ShowContextMenu(HWND hWnd, POINT pt) wchar_t buf[40] = {0}; swprintf_s(buf, L"%ld", it2->number); SearchReplace(cmd, L"%line%", buf); + swprintf_s(buf, L"%ld", it2->column); + SearchReplace(cmd, L"%column%", buf); STARTUPINFO startupInfo; PROCESS_INFORMATION processInfo; @@ -365,9 +367,14 @@ UINT CShellContextMenu::ShowContextMenu(HWND hWnd, POINT pt) wchar_t buf[40] = {0}; swprintf_s(buf, L"%ld", it->matchLinesNumbers[0]); SearchReplace(cmd, L"%line%", buf); + swprintf_s(buf, L"%ld", it->matchColumnsNumbers[0]); + SearchReplace(cmd, L"%column%", buf); } else + { SearchReplace(cmd, L"%line%", L"0"); + SearchReplace(cmd, L"%column%", L"0"); + } STARTUPINFO startupInfo; PROCESS_INFORMATION processInfo; diff --git a/src/grepWin.vcxproj b/src/grepWin.vcxproj index 7d3e65a7..24d138ff 100644 --- a/src/grepWin.vcxproj +++ b/src/grepWin.vcxproj @@ -113,7 +113,7 @@ true Windows MachineX86 - shlwapi.lib;Urlmon.lib;UxTheme.lib;%(AdditionalDependencies) + shlwapi.lib;Urlmon.lib;UxTheme.lib;Msimg32.lib;%(AdditionalDependencies) true @@ -140,7 +140,7 @@ true Windows - shlwapi.lib;Urlmon.lib;UxTheme.lib;%(AdditionalDependencies) + shlwapi.lib;Urlmon.lib;UxTheme.lib;Msimg32.lib;%(AdditionalDependencies) true @@ -172,7 +172,7 @@ true Windows MachineX86 - shlwapi.lib;Urlmon.lib;UxTheme.lib;%(AdditionalDependencies) + shlwapi.lib;Urlmon.lib;UxTheme.lib;Msimg32.lib;%(AdditionalDependencies) true @@ -202,7 +202,7 @@ true true Windows - shlwapi.lib;Urlmon.lib;UxTheme.lib;%(AdditionalDependencies) + shlwapi.lib;Urlmon.lib;UxTheme.lib;Msimg32.lib;%(AdditionalDependencies) true diff --git a/src/resource.h b/src/resource.h index 36058777..adcebf22 100644 --- a/src/resource.h +++ b/src/resource.h @@ -91,6 +91,7 @@ #define IDS_COPY_COLUMN 177 #define IDS_COPY_COLUMN_SEL 178 #define IDS_REGEXEXCEPTION 179 +#define IDS_COLUMN 180 #define IDC_SEARCHTEXT 1000 #define IDC_REGEXRADIO 1001 #define IDC_TEXTRADIO 1002 diff --git a/translations/Afrikaans.lang b/translations/Afrikaans.lang index 5feba979..abd045a7 100644 --- a/translations/Afrikaans.lang +++ b/translations/Afrikaans.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld meer gevind" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% word vervang met die pad van die lêer, %line% met die lyn om na te spring, %pattern% met die soekreeks." #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "Vang Soektog" msgid "Check for updates" msgstr "Kyk vir opdaterings" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Opdragreël om 'n redakteur op 'n spesifieke reël te begin:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Lyn" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Lyn %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Lyn %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Belarusian.lang b/translations/Belarusian.lang index db973db0..6674dd3b 100644 --- a/translations/Belarusian.lang +++ b/translations/Belarusian.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "больш %ld супадзенняў" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "" msgid "Check for updates" msgstr "" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Каманда для адкрыцця рэдактара на выбраным радку:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Радок" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Радок %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Радок %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Chinese Simplified.lang b/translations/Chinese Simplified.lang index 8836bf4c..05b606ef 100644 --- a/translations/Chinese Simplified.lang +++ b/translations/Chinese Simplified.lang @@ -44,8 +44,8 @@ msgid "%ld more matches" msgstr "还有 %ld 个匹配" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" -msgstr "%path% 将被替换为文件的路径, %line% 将被替换为要转至的行号." +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" +msgstr "%path% 将被替换为文件的路径, %line% 将被替换为要转至的行号, %column% 为行内偏移量." #. Resource IDs: (119) msgid "&About grepWin..." @@ -124,9 +124,13 @@ msgstr "输入替换搜索" msgid "Check for updates" msgstr "检查更新" +#. Resource IDs: (180) +msgid "Column" +msgstr "行内偏移" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" -msgstr "用于在指定的行来启动编辑器的命令行:" +msgid "Command line to start an editor at a specific line and in line offset:" +msgstr "用于在指定的行和行内偏移来启动编辑器的命令行:" #. Resource IDs: (1060) msgid "Content" @@ -307,8 +311,8 @@ msgstr "行号" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "行 %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "行 %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Chinese Traditional.lang b/translations/Chinese Traditional.lang index 0553a120..b1d05335 100644 --- a/translations/Chinese Traditional.lang +++ b/translations/Chinese Traditional.lang @@ -44,8 +44,8 @@ msgid "%ld more matches" msgstr "還有 %ld 個匹配" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" -msgstr "%path% 將被取代為檔案的路徑, %line% 將被取代為要轉至的行號." +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" +msgstr "%path% 將被取代為檔案的路徑, %line% 將被取代為要轉至的行號, %column% 為行内偏移量." #. Resource IDs: (119) msgid "&About grepWin..." @@ -124,9 +124,13 @@ msgstr "捕捉搜尋" msgid "Check for updates" msgstr "檢查更新" +#. Resource IDs: (180) +msgid "Column" +msgstr "行内偏移" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" -msgstr "用於在指定的行來啟動編輯器的命令:" +msgid "Command line to start an editor at a specific line and in line offset:" +msgstr "用於在指定的行和行内偏移來啟動編輯器的命令:" #. Resource IDs: (1060) msgid "Content" @@ -307,8 +311,8 @@ msgstr "行號" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "行 %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "行 %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Dutch.lang b/translations/Dutch.lang index 2b6b13a3..c1731481 100644 --- a/translations/Dutch.lang +++ b/translations/Dutch.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld meer overeenkomsten" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% wordt vervangen door het pad van het bestand, %line% door de juiste regel" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "Zoekopdracht vastleggen" msgid "Check for updates" msgstr "Controleren op updates" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Opdrachtregel om een Editor op een specifieke regel te openen" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Regel" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Regel %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Regel %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/English.lang b/translations/English.lang index d5b051be..77d335e6 100644 --- a/translations/English.lang +++ b/translations/English.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "" msgid "Check for updates" msgstr "" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "" #. Resource IDs: (1060) @@ -307,7 +311,7 @@ msgstr "" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" +msgid "Line %5ld : %s\n" msgstr "" #. Resource IDs: (135) diff --git a/translations/French.lang b/translations/French.lang index 60f40ce7..d889e86f 100644 --- a/translations/French.lang +++ b/translations/French.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld autres correspondances" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% est remplacé par le chemin du fichier, %line% par la ligne à atteindre" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "" msgid "Check for updates" msgstr "" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Commande de lancement d'un éditeur à une ligne spécifique :" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Ligne" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Ligne %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Ligne %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/German.lang b/translations/German.lang index 36edadd6..30b1263b 100644 --- a/translations/German.lang +++ b/translations/German.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld mehr Übereinstimmungen" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% wird durch den Pfad der Datei ersetzt, %line% mit der Zeile, zu der gesprungen wird." #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "Resultat-Suche" msgid "Check for updates" msgstr "Auf Updates prüfen" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Befehlszeile, um einen Editor an einer spezifischen Zeile zu starten:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Zeile" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Zeile %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Zeile %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Greek.lang b/translations/Greek.lang index d8e789f9..64cdefd5 100644 --- a/translations/Greek.lang +++ b/translations/Greek.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld περισσότερα ταιριάσματα" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "Το %path% αντικαθίσταται με τη διαδρομή του αρχείου, το %line% με τη γραμμή μετάβασης" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "" msgid "Check for updates" msgstr "" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Εντολή για έναρξη του επεξεργαστή κειμένου σε συγκεκριμένη γραμμή:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Γραμμή" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Γραμμή %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Γραμμή %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Hindi.lang b/translations/Hindi.lang index dbfebf7d..0112ec90 100644 --- a/translations/Hindi.lang +++ b/translations/Hindi.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld ज्यादा मिलान नतीजे" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% फ़ाइल के पथ से बदल जाएगा, %line% जिस रेखा पे कूदना है उससे" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "खोज कैप्चर करें" msgid "Check for updates" msgstr "अद्यतन जांच" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "एक निश्चित रेखा पर संपादक को शुरू करें के लिए रेखा को आदेश दें:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "रेखा" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "रेखा %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "रेखा %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Hungarian.lang b/translations/Hungarian.lang index 90772c0d..73467c9a 100644 --- a/translations/Hungarian.lang +++ b/translations/Hungarian.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld további találat" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% helyébe a fájl elérési útvonala, %line% helyébe az a sor lép, amelyre ugrani kell" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "Keresés rögzítése" msgid "Check for updates" msgstr "Frissítések ellenőrzése" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Parancs, ami a szerkesztőt egy bizonyos sornál nyitja meg:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Sor" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "%5ld : %30s sor\n" +msgid "Line %5ld : %s\n" +msgstr "%5ld : %s sor\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Italian.lang b/translations/Italian.lang index 5ec3949a..e9afec9b 100644 --- a/translations/Italian.lang +++ b/translations/Italian.lang @@ -46,7 +46,7 @@ msgid "%ld more matches" msgstr "%ld ulteriori risultati" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% viene sostituito dal percorso del file, %line% dalla riga a cui saltare" #. Resource IDs: (119) @@ -126,8 +126,12 @@ msgstr "Cerca cattura" msgid "Check for updates" msgstr "Controlla gli aggiornamenti" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Linea di comando per avviare un editor su una riga specifica:" #. Resource IDs: (1060) @@ -309,8 +313,8 @@ msgstr "Riga" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Riga %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Riga %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Japanese.lang b/translations/Japanese.lang index b906b040..dff0ff58 100644 --- a/translations/Japanese.lang +++ b/translations/Japanese.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld か所のさらなる一致" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% はファイルのパス - %line% は移動先の行番号 で置換されます" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "キャプチャと後方参照を使用" msgid "Check for updates" msgstr "最新版を確認" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "指定行をエディタで開くためのコマンドライン:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "行番号" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "行 %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "行 %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Korean.lang b/translations/Korean.lang index 677ab23b..6fb93495 100644 --- a/translations/Korean.lang +++ b/translations/Korean.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld개 더 많은 일치" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path%가 파일의 경로로 대체되었습니다. %line%는 이동할 행으로 대체되었습니다" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "캡쳐 검색" msgid "Check for updates" msgstr "업데이트 확인" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "특정 줄에서 편집기를 시작하는 명령줄:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "줄" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "줄 %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "줄 %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Polish.lang b/translations/Polish.lang index 93627809..66489494 100644 --- a/translations/Polish.lang +++ b/translations/Polish.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "... %ld więcej dopasowań" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% jest zastępowana ścieżką pliku, %line% z linią, aby przejść do." #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "Przechwyć wyszukiwanie" msgid "Check for updates" msgstr "Sprawdź aktualizacje" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Wiersz poleceń uruchamiania edytora w określonej linii:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Linia" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Linia %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Linia %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Portuguese Brazilian.lang b/translations/Portuguese Brazilian.lang index b1eb4c5b..27c08452 100644 --- a/translations/Portuguese Brazilian.lang +++ b/translations/Portuguese Brazilian.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld mais encontrados" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% é substituído com o caminho do arquivo, %line% a linha para pular" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "Pesquisar capturado" msgid "Check for updates" msgstr "Verificar por atualizações" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Linha de comando para iniciar o editor em uma linha específica:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Linha" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Linha %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Linha %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Portuguese.lang b/translations/Portuguese.lang index fd82fbdb..ad380722 100644 --- a/translations/Portuguese.lang +++ b/translations/Portuguese.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld mais correspondências" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "" msgid "Check for updates" msgstr "" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Linha de comando para iniciar um editor numa linha específica:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Linha" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Linha %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Linha %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Russian.lang b/translations/Russian.lang index da5831a9..c755b40d 100644 --- a/translations/Russian.lang +++ b/translations/Russian.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "больше %ld совпадений" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% - заменяется на путь к файлу, %line% - на номер строки" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "Захватить найденное" msgid "Check for updates" msgstr "Проверять обновления" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Команда для открытия выбранной строки в редакторе:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Строка" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Строка %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Строка %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Slovak.lang b/translations/Slovak.lang index 11a00d2e..cec571e5 100644 --- a/translations/Slovak.lang +++ b/translations/Slovak.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld viac výskytov" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "" msgid "Check for updates" msgstr "" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Príkazový riadok na spustenie editora na konkrétnom riadku:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Riadok" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Riadok %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Riadok %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Spanish Mexican.lang b/translations/Spanish Mexican.lang index 20fc14a8..95744c4c 100644 --- a/translations/Spanish Mexican.lang +++ b/translations/Spanish Mexican.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld más resultados" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% es reemplazada con la ruta del archivo, %line% por la línea a ir, %pattern% con la cadena de búsqueda." #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "Capture búsqueda" msgid "Check for updates" msgstr "Checar actualizaciones" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Línea de comandos para iniciar un editor en la línea especificada:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Línea" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Línea %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Línea %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Spanish.lang b/translations/Spanish.lang index 66682565..025f6b1a 100644 --- a/translations/Spanish.lang +++ b/translations/Spanish.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld mas resultados" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "" msgid "Check for updates" msgstr "" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Linea de comandos para iniciar un editor en la linea especificada:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Linea" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Linea %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Linea %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Swedish.lang b/translations/Swedish.lang index e598514d..d6fe6e57 100644 --- a/translations/Swedish.lang +++ b/translations/Swedish.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld fler träffar" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% ersätts med sökväg till filen, %line% med raden att hoppa till, %pattern% med söksträngen." #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "" msgid "Check for updates" msgstr "" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Kommando för att starta editor på en secifik rad:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Rad" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Rad %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Rad %5ld : %s\n" #. Resource IDs: (135) msgid "Matches" diff --git a/translations/Turkish.lang b/translations/Turkish.lang index 84a8eae4..b13f5f90 100644 --- a/translations/Turkish.lang +++ b/translations/Turkish.lang @@ -44,7 +44,7 @@ msgid "%ld more matches" msgstr "%ld daha fazla eşleşme" #. Resource IDs: (1069) -msgid "%path% is replaced with the path of the file, %line% with the line to jump to" +msgid "%path% is replaced with the path of the file, %line% with the line to jump to, %column% with in line offset" msgstr "%path% dosyanın yolu, %line% ile atlanacak satırla değiştirilir" #. Resource IDs: (119) @@ -124,8 +124,12 @@ msgstr "" msgid "Check for updates" msgstr "" +#. Resource IDs: (180) +msgid "Column" +msgstr "" + #. Resource IDs: (1068) -msgid "Command line to start an editor at a specific line:" +msgid "Command line to start an editor at a specific line and in line offset:" msgstr "Belirli bir satırda bir editör başlatmak için komut satırı:" #. Resource IDs: (1060) @@ -307,8 +311,8 @@ msgstr "Çizgi" #. Resource IDs: (150) #, c-format -msgid "Line %5ld : %30s\n" -msgstr "Çizgi %5ld : %30s\n" +msgid "Line %5ld : %s\n" +msgstr "Çizgi %5ld : %s\n" #. Resource IDs: (135) msgid "Matches"