10 #include "message.hpp"
12 #include "pathmix.hpp"
15 #include "execute.hpp"
16 #include "manager.hpp"
17 #include "ConfigRW.hpp"
18 #include "HotkeyLetterDialog.hpp"
19 #include "MountInfo.h"
23 #define HOTKEYS_SECTION "MountsHotkeys"
28 static wchar_t DefaultHotKey(int id
, const FARString
&path
)
44 static std::string
SettingsKey(int id
)
46 return StrPrintf("%08x", id
);
49 static int GenerateIdFromPath(const FARString
&path
)
51 if (path
== WGOOD_SLASH
)
54 const std::string
&path_mb
= path
.GetMB();
55 const uint64_t id64
= crc64(0, (unsigned char *)path_mb
.c_str(), path_mb
.size());
56 uint32_t out
= (uint32_t)(id64
^ (id64
>> 32));
57 if (out
== ID_ROOT
|| out
== ID_HOME
|| out
== ID_ANOTHER
) {
65 Enum::Enum(FARString
&another_curdir
)
67 bool has_rootfs
= false;
68 if (Opt
.ChangeDriveMode
& DRIVE_SHOW_MOUNTS
)
70 AddMounts(has_rootfs
);
72 AddFavorites(has_rootfs
);
75 emplace(begin(), Entry(WGOOD_SLASH
, Msg::MountsRoot
, false, ID_ROOT
));
78 emplace(begin(), Entry( GetMyHome(), Msg::MountsHome
, false, ID_HOME
));
79 emplace(begin(), Entry( another_curdir
, Msg::MountsOther
, false, ID_ANOTHER
));
81 ConfigReader
cfg_reader(HOTKEYS_SECTION
);
82 for (auto &m
: *this) {
83 if (max_path
< m
.path
.CellsCount())
84 max_path
= m
.path
.CellsCount();
85 if (max_col3
< m
.col3
.CellsCount())
86 max_col3
= m
.col3
.CellsCount();
87 if (max_col2
< m
.col2
.CellsCount())
88 max_col2
= m
.col2
.CellsCount();
89 wchar_t def_hk
[] = {DefaultHotKey(m
.id
, m
.path
), 0};
90 auto hk
= cfg_reader
.GetString(SettingsKey(m
.id
), def_hk
);
91 m
.hotkey
= hk
.IsEmpty() ? 0 : *hk
.CPtr();
95 static void ExpandMountpointInfo(const Mountpoint
&mp
, FARString
&str
)
100 } else if (mp
.read_only
) {
103 ReplaceStrings(str
, L
"$S", val
);
105 FileSizeToStr(val
, mp
.total
, -1, COLUMN_ECONOMIC
| COLUMN_FLOATSIZE
| COLUMN_SHOWBYTESINDEX
);
106 ReplaceStrings(str
, L
"$T", val
);
108 FileSizeToStr(val
, mp
.avail
, -1, COLUMN_ECONOMIC
| COLUMN_FLOATSIZE
| COLUMN_SHOWBYTESINDEX
);
109 ReplaceStrings(str
, L
"$A", val
);
111 FileSizeToStr(val
, mp
.free_
, -1, COLUMN_ECONOMIC
| COLUMN_FLOATSIZE
| COLUMN_SHOWBYTESINDEX
);
112 ReplaceStrings(str
, L
"$F", val
);
114 FileSizeToStr(val
, mp
.total
- mp
.free_
, -1, COLUMN_ECONOMIC
| COLUMN_FLOATSIZE
| COLUMN_SHOWBYTESINDEX
);
115 ReplaceStrings(str
, L
"$U", val
);
118 val
.Format(L
"%lld", (mp
.avail
* 100) / mp
.total
);
121 ReplaceStrings(str
, L
"$a", val
);
124 val
.Format(L
"%lld", (mp
.free_
* 100) / mp
.total
);
127 ReplaceStrings(str
, L
"$f", val
);
130 val
.Format(L
"%lld", ((mp
.total
- mp
.free_
) * 100) / mp
.total
);
133 ReplaceStrings(str
, L
"$u", val
);
136 ReplaceStrings(str
, L
"$N", val
);
139 ReplaceStrings(str
, L
"$D", val
);
144 std::vector
<size_t> _maximums
;
146 static bool IsWordDiv(wchar_t c
)
148 return !iswalnum(c
) && c
!= L
'.' && c
!= L
',';
151 static size_t LeftWordLength(const FARString
&str
, size_t pos
)
154 while (out
>= 0 && !IsWordDiv(str
.At(out
))) {
157 return ssize_t(pos
) - out
;
160 static size_t RightWordLength(const FARString
&str
, size_t pos
)
163 while (out
< str
.GetLength() && !IsWordDiv(str
.At(out
))) {
170 void Analyze(const FARString
&str
)
173 const int str_len
= str
.GetLength();
174 for (int i
= str_len
- 2; i
>= 0; --i
) {
175 if (str
.At(i
) == '$' && ((str
.At(i
+ 1) == '<' && i
>= 0)
176 || (str
.At(i
+ 1) == '>' && i
+ 2 <= str_len
))
178 const size_t len
= (str
.At(i
+ 1) == '>')
179 ? RightWordLength(str
, i
+ 2) : LeftWordLength(str
, i
- 1);
180 if (_maximums
.size() <= m
) {
181 _maximums
.emplace_back(len
);
182 } else if (_maximums
[m
] < len
) {
190 void Apply(FARString
&str
)
193 const int str_len
= str
.GetLength();
194 for (int i
= str_len
- 2; i
>= 0; --i
) {
195 if (str
.At(i
) == '$' && ((str
.At(i
+ 1) == '<' && i
>= 0)
196 || (str
.At(i
+ 1) == '>' && i
+ 2 <= str_len
))
198 const size_t len
= (str
.At(i
+ 1) == '>')
199 ? RightWordLength(str
, i
+ 2) : LeftWordLength(str
, i
- 1);
200 str
.Replace(i
, 2, L
' ', _maximums
[m
] - len
);
207 void Enum::AddMounts(bool &has_rootfs
)
210 for (const auto &mp
: mi
.Enum()) {
214 e
.col2
= Opt
.ChangeDriveColumn2
;
215 e
.col3
= Opt
.ChangeDriveColumn3
;
216 ExpandMountpointInfo(mp
, e
.col2
);
217 ExpandMountpointInfo(mp
, e
.col3
);
219 if (e
.path
== WGOOD_SLASH
) {
222 e
.unmountable
= true;
224 e
.id
= GenerateIdFromPath(e
.path
);
227 // apply replace $> and $< spacers
228 Aligner al_path
, al_col2
, al_col3
;
229 for (const auto &e
: *this) {
230 al_path
.Analyze(e
.path
);
231 al_col2
.Analyze(e
.col2
);
232 al_col3
.Analyze(e
.col3
);
234 for (auto &e
: *this) {
235 al_path
.Apply(e
.path
);
236 al_col2
.Apply(e
.col2
);
237 al_col3
.Apply(e
.col3
);
241 void Enum::AddFavorites(bool &has_rootfs
)
243 std::ifstream
favis(InMyConfig("favorites"));
244 if (favis
.is_open()) {
246 while (std::getline(favis
, line
)) {
247 StrTrim(line
, " \t\r\n");
248 if (line
.empty() || line
.front() == '#') {
251 Environment::ExpandString(line
, true, true);
252 std::vector
<std::string
> sublines
;
253 StrExplode(sublines
, line
, "\n");
254 for (const auto &subline
: sublines
) {
255 std::vector
<std::string
> parts
;
256 StrExplode(parts
, subline
, "\t");
257 if (!parts
.empty()) {
260 e
.path
= parts
.front();
261 if (parts
.size() > 1) {
262 e
.col3
= parts
.back();
263 if (parts
.size() > 2) {
267 e
.id
= GenerateIdFromPath(e
.path
);
268 if (e
.path
== WGOOD_SLASH
) {
271 } else if (*e
.path
.CPtr() == L
'/') {
272 e
.unmountable
= true;
281 bool Unmount(const FARString
&path
, bool force
)
283 std::string cmd
= GetMyScriptQuoted("unmount.sh");
285 cmd
+= EscapeCmdStr(Wide2MB(path
));
290 int r
= farExecuteA(cmd
.c_str(), 0);
292 auto *current_frame
= FrameManager
->GetCurrentFrame();
294 FrameManager
->RefreshFrame(current_frame
);
300 void EditHotkey(const FARString
&path
, int id
)
302 wchar_t def_hk
[] = {DefaultHotKey(id
, path
), 0};
303 const auto &Key
= SettingsKey(id
);
304 const auto &Setting
= ConfigReader(HOTKEYS_SECTION
).GetString(Key
, def_hk
);
305 WCHAR Letter
[2] = {Setting
.IsEmpty() ? 0 : Setting
[0], 0};
306 if (HotkeyLetterDialog(Msg::LocationHotKeyTitle
, path
.CPtr(), Letter
[0])) {
307 ConfigWriter
cw(HOTKEYS_SECTION
);
309 cw
.SetString(Key
, Letter
);