17 Commits

Author SHA1 Message Date
Vitaly Zdanevich
5478f290a1 README.org: fzf example: preview window make bigger
Was 50%:50% and by UX we do not need the half of the screen for the dictionary name.
2025-10-07 23:44:02 +03:00
Evgeniy A. Dushistov
9c77e91006 fix: include stdio for popen 2025-08-17 14:29:03 +03:00
Evgeniy A. Dushistov
b74bc2478a chore: document integration with readline
fixes #27
2025-08-17 14:22:40 +03:00
Vitaly Zdanevich
58c48988f6 README.org: add fzf 2025-08-17 13:58:02 +03:00
NorwayFun
07cd873e9d po: Adding Georgian translation 2025-08-17 13:52:26 +03:00
Evgeniy A. Dushistov
4545473da9 refactor: use more clear way to concat strings 2025-08-17 13:51:53 +03:00
Evgeniy A. Dushistov
849f0ed1ac fix: memory leak instroduced in #110 2025-08-17 13:51:53 +03:00
Evgeniy A. Dushistov
d5e1eb4d93 test: use actions/checkout@v4 2025-08-17 13:32:56 +03:00
Evgeniy A. Dushistov
3a4b76124c test: make sure cmake 3.10 works 2025-08-17 13:32:56 +03:00
Evgeniy A. Dushistov
6eaebaaa2f test: use cmake from distributive 2025-08-17 13:32:56 +03:00
Evgeniy A. Dushistov
e24722b8fc test: ubuntu 20.04 is missing, use 22.04 instead 2025-08-17 13:32:56 +03:00
Evgeniy A. Dushistov
c57ef6e916 fix: use READLINE_(INCLUDE_DIR|LIBRARY) if WITH_READLINE==True 2025-08-17 13:32:56 +03:00
Evgeniy A. Dushistov
24c08365c4 fix: set given invalid arguments for CACHE mode: missing type or docstring 2025-08-17 13:32:56 +03:00
Evgeniy A. Dushistov
8f77ede167 chore: update requirement for cmake to 3.10, to make modern cmake happy
and fix build on latest Ubuntu (24.04)
2025-08-17 13:32:56 +03:00
Evgeniy A. Dushistov
3a8ab1d5c3 test: install missed libglib2.0-dev on CI machine 2025-08-17 13:32:56 +03:00
Norayr Chilingarian
5887505185 Fix build with GCC 14 and modern glib: const correctness and deprecated API
- Use 'const gchar*' for result of g_utf8_next_char() to satisfy GCC 14's stricter const rules
- Remove incorrect g_free() on non-allocated pointer from g_utf8_next_char()
- Replace deprecated g_pattern_match_string() with g_pattern_spec_match_string()
2025-08-17 12:48:04 +03:00
Xiao Pan
beebb0faa7 fix: read_history() multiple times will add repeat histories to history lists
Issue Description:

When sdcv found multiple items, whatever your choice is, sdcv will add
double the current history entries to history file. For example, if
current history is "a\nb", you search akjk and there's multiple results,
whatever you choose, even -1,  after this is done, the history file will
be rewritten to "a\nb\nakjk\na\nb", note here \n is newline character.
So if you have 500 lines of history, you search akjk and there's
multiple results, you choose -1, after done there's 1001 lines of
history.

How to reproduce:

You can download this dictionary file
https://github.com/skywind3000/ECDICT/releases/download/1.0.28/ecdict-stardict-28.zip
and put into your dictionary directory, on Arch, with AUR, you can
install from https://aur.archlinux.org/packages/stardict-ecdict. Then,
make sure you also add the dictionary name to ~/.config/sdcv_ordering if
you have one. Add some lines to your history file if you do not have.
Then search for "akjk" with sdcv, e,g, `sdcv akjk`, then it will prompt
you to choose, you can choose -1, then ctrl-d to exit. Expected result
is history file add akjk at the end. Actual result is history file now
contain original content + akjk + original content duplicate as I
described in the issue description.

Fix and reasons:

I'm a hobbyist and I'm not a professional, I haven't use C++ for years
so many of my writings is very likely wrong. After some trail and error,
I found that call read_history() multiple times will add repeat
histories to history lists. In the commit d2327e2, a new IReadLine
object is created (note name changes, also note I know this description
of a IReadLine object is wrong). Here's a permalink:
49c8094b53/src/libwrapper.cpp (L418).
The problem of this new IReadLine object `choice_readline` is it called
read_history() again from ./src/readline.cpp constructor, because
there's already a IReadLine object `io` constructed at ./src/sdcv.cpp.
When read_history() is called twice, there's a "history lists" read from
history file first then append from history file again, so when you
destruct IReadLine object with write_history() in ./src/readline.cpp,
the history file contain duplicate content after write. Here are
permalinks:
49c8094b53/src/readline.cpp (L88),
and
49c8094b53/src/readline.cpp (L94).

So my fix is to just to use `io` IReadLine object and not to create a
new `choice_readline` object.

Misc:

During my trial and errors process, I made an example code to show
read_history()'s weird behavior. I did not dig deeper, I just guess
maybe there's some kind of werid history list as mentioned in
https://tiswww.cwru.edu/php/chet/readline/history.html#History-List-Management.

Here's the example code a.c, note you need to include stdio.h,
readline/history.h, and readline/readline.h. I did not include them here
because commit message seems will make them comment.
```c
...
int main (void)
{
	rl_readline_name="learn_readline";
	using_history();
	read_history("/home/xyz/test/learn_readline/history.txt");
	write_history("/home/xyz/test/learn_readline/history2.txt");
	{
		rl_readline_name="learn_readline";
		using_history();
		read_history("/home/xyz/test/learn_readline/history.txt");
		write_history("/home/xyz/test/learn_readline/history3.txt");
	}
	write_history("/home/xyz/test/learn_readline/history4.txt");
	return 0;
}
```
Here's the content of history.txt:
```
a
b
```
After build and run, as you can guess, history2.txt is same as
history.txt. But history3.txt and history4.txt content are:
```
a
b
a
b
```

Signed-off-by: Xiao Pan <xyz@flylightning.xyz>
2024-08-15 13:08:33 +03:00
6 changed files with 200 additions and 26 deletions

View File

@@ -20,15 +20,12 @@ jobs:
fail-fast: true fail-fast: true
matrix: matrix:
os: [ubuntu-20.04, ubuntu-latest] os: [ubuntu-22.04, ubuntu-latest]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: jwlawson/actions-setup-cmake@v2
with: with:
submodules: 'recursive' cmake-version: '3.10'
- uses: jwlawson/actions-setup-cmake@v1.4
if: matrix.os != 'ubuntu-latest'
with:
cmake-version: '3.5.1'
github-api-token: ${{ secrets.GITHUB_TOKEN }} github-api-token: ${{ secrets.GITHUB_TOKEN }}
- name: Check versions - name: Check versions
run: | run: |
@@ -37,6 +34,10 @@ jobs:
gcc --version gcc --version
echo "end of versions checking" echo "end of versions checking"
shell: bash shell: bash
- uses: awalsh128/cache-apt-pkgs-action@v1
with:
packages: libglib2.0-dev
version: 1.0
- name: Run tests - name: Run tests
run: | run: |
set -e set -e

View File

@@ -1,7 +1,7 @@
project(sdcv) cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
cmake_policy(VERSION 3.10)
cmake_minimum_required(VERSION 3.5 FATAL_ERROR) project(sdcv)
cmake_policy(VERSION 3.5)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_CXX_STANDARD_REQUIRED True)
@@ -27,7 +27,8 @@ if (WITH_READLINE)
find_path(READLINE_INCLUDE_DIR readline/readline.h) find_path(READLINE_INCLUDE_DIR readline/readline.h)
find_library(READLINE_LIBRARY NAMES readline) find_library(READLINE_LIBRARY NAMES readline)
if (NOT (READLINE_INCLUDE_DIR AND READLINE_LIBRARY)) if (NOT (READLINE_INCLUDE_DIR AND READLINE_LIBRARY))
set(WITH_READLINE False CACHE FORCE) message(STATUS "readline library not FOUND, disable it's usage")
set(WITH_READLINE False CACHE BOOL "Use readline library" FORCE)
endif () endif ()
endif (WITH_READLINE) endif (WITH_READLINE)
@@ -82,10 +83,13 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake
include_directories( include_directories(
${ZLIB_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}
${GLIB2_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS}
${READLINE_INCLUDE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src/lib ${CMAKE_CURRENT_SOURCE_DIR}/src/lib
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
) )
if (WITH_READLINE)
include_directories(${READLINE_INCLUDE_DIR})
endif()
# #
# Packing stuff # Packing stuff
@@ -107,8 +111,10 @@ add_executable(sdcv ${sdcv_SRCS})
target_link_libraries(sdcv target_link_libraries(sdcv
${GLIB2_LIBRARIES} ${GLIB2_LIBRARIES}
${ZLIB_LIBRARIES} ${ZLIB_LIBRARIES}
${READLINE_LIBRARY}
) )
if (WITH_READLINE)
target_link_libraries(sdcv ${READLINE_LIBRARY})
endif()
if (ENABLE_NLS) if (ENABLE_NLS)
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "locale") set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "locale")
endif () endif ()

View File

@@ -29,6 +29,26 @@ To report bugs use https://github.com/Dushistov/sdcv/issues ,
if it is not possible you can report it via email to dushistov at mail dot ru. if it is not possible you can report it via email to dushistov at mail dot ru.
Be sure to include the word "sdcv" somewhere in the "Subject:" field. Be sure to include the word "sdcv" somewhere in the "Subject:" field.
* Integration with [[https://github.com/junegunn/fzf][fzf]]
Useful when you have multiple dictionaries
#+BEGIN_SRC sh
fzf --prompt="Dict: " \
--phony \
--bind "enter:reload(sdcv {q} -n --json | jq '.[].dict' -r)" \
--preview "sdcv {q} -en --use-dict={}" \
--preview-window=right:70%:wrap \
< <(echo)
#+END_SRC
* Integration with readline
This lines can be added to inputrc file (~/.inputrc, /etc/inputrc),
to abort multiply usage with ESC:
#+begin_src
$if sdcv
"\e\e": "-1\n"
$endif
#+end_src
* Notes to developer * Notes to developer
** make source code release ** make source code release
#+BEGIN_SRC sh #+BEGIN_SRC sh

147
po/ka.po Normal file
View File

@@ -0,0 +1,147 @@
# Georgian translation for sdcv.
# Copyright (C) 2025 sdcv authors
# This file is distributed under the same license as the sdcv project.
# Temuri Doghonadze <temuri.doghonadze@gmail.com>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: sdcv 0.5\n"
"Report-Msgid-Bugs-To: dushistov@mail.ru\n"
"POT-Creation-Date: 2020-08-14 12:58+0300\n"
"PO-Revision-Date: 2025-01-26 03:17+0100\n"
"Last-Translator: Temuri Doghonadze <temuri.doghonadze@gmail.com>\n"
"Language-Team: Georgian <(nothing)>\n"
"Language: ka\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.5\n"
#: ../src/libwrapper.cpp:300
msgid "popen failed"
msgstr "popen ჩავარდა"
#: ../src/libwrapper.cpp:341
#, c-format
msgid "Can not convert %s to utf8.\n"
msgstr "%s-ის utf8-ში გადაყვანა შეუძლებელია.\n"
#: ../src/libwrapper.cpp:399 ../src/libwrapper.cpp:433
#, c-format
msgid "Found %zu items, similar to %s.\n"
msgstr "აღმოჩენილია %zu ელემენტი, რომელიც %s-ს ჰგავს.\n"
#: ../src/libwrapper.cpp:417
msgid "Your choice[-1 to abort]: "
msgstr "თქვენი არჩევანი[-1 გასაუქმებლად]: "
#: ../src/libwrapper.cpp:427
#, c-format
msgid ""
"Invalid choice.\n"
"It must be from 0 to %zu or -1.\n"
msgstr ""
"არასწორი არჩევანი.\n"
"უნდა იყოს 0-დან %zu-მდე, ან -1.\n"
#: ../src/libwrapper.cpp:446
#, c-format
msgid "Nothing similar to %s, sorry :(\n"
msgstr "%s-ს არაფერი ჰგავს :(\n"
#: ../src/sdcv.cpp:89
msgid "display version information and exit"
msgstr "ვერსიის ჩვენება და გასვლა"
#: ../src/sdcv.cpp:91
msgid "display list of available dictionaries and exit"
msgstr "ხელმისაწვდომი ლექსიკონების ჩვენება და გასვლა"
#: ../src/sdcv.cpp:93
msgid "for search use only dictionary with this bookname"
msgstr "ძებნისთვის, მხოლოდ, ამ სახელის მქონე ლექსიკონის გამოყენება"
#: ../src/sdcv.cpp:94
msgid "bookname"
msgstr "ლექსიკონის_სახელი"
#: ../src/sdcv.cpp:96
msgid "for use in scripts"
msgstr "სკრიპტებში გამოსაყენებლად"
#: ../src/sdcv.cpp:98
msgid "print the result formatted as JSON"
msgstr "შედეგების JSON ფორმატში გამოტანა"
#: ../src/sdcv.cpp:100
msgid "do not fuzzy-search for similar words, only return exact matches"
msgstr ""
"მსგავსი სიტყვებისთვის არაზუსტი ძებნა გამოყენებული არ იქნება. "
"დაბრუნდება, მხოლოდ, ზუსტი დამთხვევები"
#: ../src/sdcv.cpp:102
msgid "output must be in utf8"
msgstr "გამოტანა utf8-ში უნდა იყოს"
#: ../src/sdcv.cpp:104
msgid "input of sdcv in utf8"
msgstr "პროგრამაში შეყვანა utf8 -ში"
#: ../src/sdcv.cpp:106
msgid "use this directory as path to stardict data directory"
msgstr ""
"ამ საქაღალდის გამოყენება stardict-ის მონაცემების საქაღალდის ბილიკად"
#: ../src/sdcv.cpp:107
msgid "path/to/dir"
msgstr "ბილიკი/სასურველ/საქაღალდემდე"
#: ../src/sdcv.cpp:109
msgid ""
"only use the dictionaries in data-dir, do not search in user and system "
"directories"
msgstr ""
"ლექსიკონების, მხოლოდ, data-dir-დან გამოყენება. მომხმარებლის და სისტემურ "
"საქაღალდეებში ძებნა არ მოხდება"
#: ../src/sdcv.cpp:111
msgid "colorize the output"
msgstr "ფერებში გამოტანა"
#: ../src/sdcv.cpp:116
msgid " words"
msgstr " სიტყვა"
#: ../src/sdcv.cpp:122
#, c-format
msgid "Invalid command line arguments: %s\n"
msgstr "არასწორი ბრძანების სტრიქონის არგუმენტები: %s\n"
#: ../src/sdcv.cpp:128
#, c-format
msgid "Console version of Stardict, version %s\n"
msgstr "Startdict-ის კონსოლის ვერსია. ვერსია %s\n"
#: ../src/sdcv.cpp:206
#, c-format
msgid "g_mkdir failed: %s\n"
msgstr "g_mkdir ჩავარდა: %s\n"
#: ../src/sdcv.cpp:222
msgid "Enter word or phrase: "
msgstr "შეიყვანეთ სიტყვა ან ფრაზა: "
#: ../src/sdcv.cpp:230
#, c-format
msgid "There are no words/phrases to translate.\n"
msgstr "სათარგმნი სიტყვების/ფრაზების გარეშე.\n"
#: ../src/sdcv.cpp:242
#, c-format
msgid "Dictionary's name Word count\n"
msgstr "ლექსიკონის სახელი სიტყვების რაოდენობა\n"
#: ../src/utils.cpp:48
#, c-format
msgid "Can not convert %s to current locale.\n"
msgstr "ვერ გადავიყვანე %s მიმდინარე ლოკალში.\n"

View File

@@ -23,6 +23,7 @@
#endif #endif
#include <cstring> #include <cstring>
#include <cstdio> //for popen
#include <map> #include <map>
#include <memory> #include <memory>
@@ -415,10 +416,9 @@ search_result Library::process_phrase(const char *loc_str, IReadLine &io, bool f
colorize_output_ ? ESC_END : ""); colorize_output_ ? ESC_END : "");
} }
int choise; int choise;
std::unique_ptr<IReadLine> choice_readline(create_readline_object());
for (;;) { for (;;) {
std::string str_choise; std::string str_choise;
choice_readline->read(_("Your choice[-1 to abort]: "), str_choise); io.read(_("Your choice[-1 to abort]: "), str_choise);
sscanf(str_choise.c_str(), "%d", &choise); sscanf(str_choise.c_str(), "%d", &choise);
if (choise >= 0 && choise < int(res_list.size())) { if (choise >= 0 && choise < int(res_list.size())) {
sdcv_pager pager; sdcv_pager pager;

View File

@@ -989,7 +989,7 @@ bool Dict::LookupWithRule(GPatternSpec *pspec, glong *aIndex, int iBuffLen)
int iIndexCount = 0; int iIndexCount = 0;
for (guint32 i = 0; i < narticles() && iIndexCount < (iBuffLen - 1); i++) for (guint32 i = 0; i < narticles() && iIndexCount < (iBuffLen - 1); i++)
if (g_pattern_match_string(pspec, get_key(i))) if (g_pattern_spec_match_string(pspec, get_key(i)))
aIndex[iIndexCount++] = i; aIndex[iIndexCount++] = i;
aIndex[iIndexCount] = -1; // -1 is the end. aIndex[iIndexCount] = -1; // -1 is the end.
@@ -1047,12 +1047,12 @@ bool Libs::LookupSimilarWord(const gchar *sWord, std::set<glong> &iWordIndices,
} }
// Upper the first character and lower others. // Upper the first character and lower others.
if (!bFound) { if (!bFound) {
gchar *nextchar = g_utf8_next_char(sWord); const gchar *rest = g_utf8_next_char(sWord);
gchar *firstchar = g_utf8_strup(sWord, nextchar - sWord); gchar *firstchar = g_utf8_strup(sWord, rest - sWord);
nextchar = g_utf8_strdown(nextchar, -1); gchar *rest_lowercase = g_utf8_strdown(rest, -1);
casestr = g_strdup_printf("%s%s", firstchar, nextchar); casestr = g_strconcat(firstchar, rest_lowercase, nullptr);
g_free(rest_lowercase);
g_free(firstchar); g_free(firstchar);
g_free(nextchar);
if (strcmp(casestr, sWord)) { if (strcmp(casestr, sWord)) {
if (oLib[iLib]->Lookup(casestr, iWordIndices)) if (oLib[iLib]->Lookup(casestr, iWordIndices))
bFound = true; bFound = true;