1 /***************************************************************************
2 * Copyright (C) 2008-2017 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #ifndef NCMPCPP_HAVE_FORMAT_IMPL_H
22 #define NCMPCPP_HAVE_FORMAT_IMPL_H
24 #include <boost/variant.hpp>
26 #include "curses/menu.h"
27 #include "curses/strbuffer.h"
30 #include "utility/functional.h"
31 #include "utility/wide_string.h"
35 // Commutative binary operation such that:
36 // - Empty + Empty = Empty
37 // - Empty + Missing = Missing
39 // - Missing + Missing = Missing
40 // - Missing + Ok = Missing
42 inline Result
&operator+=(Result
&base
, Result result
)
44 if (base
== Result::Missing
|| result
== Result::Missing
)
45 base
= Result::Missing
;
46 else if (base
== Result::Ok
|| result
== Result::Ok
)
51 /*inline std::ostream &operator<<(std::ostream &os, Result r)
68 template <typename CharT
, typename OutputT
, typename SecondOutputT
= OutputT
>
69 struct Printer
: boost::static_visitor
<Result
>
71 typedef std::basic_string
<CharT
> StringT
;
73 Printer(OutputT
&os
, const MPD::Song
*song
, SecondOutputT
*second_os
, const unsigned flags
)
76 , m_output_switched(false)
77 , m_second_os(second_os
)
82 Result
operator()(const StringT
&s
)
93 Result
operator()(const NC::Color
&c
)
95 if (m_flags
& Flags::Color
)
100 Result
operator()(NC::Format fmt
)
102 if (m_flags
& Flags::Format
)
104 return Result::Empty
;
107 Result
operator()(OutputSwitch
)
110 m_output_switched
= true;
114 Result
operator()(const SongTag
&st
)
117 if (m_flags
& Flags::Tag
&& m_song
!= nullptr)
119 tags
= convertString
<CharT
, char>::apply(
120 m_song
->getTags(st
.function())
125 if (st
.delimiter() > 0)
127 // shorten date/length by simple truncation
128 if (st
.function() == &MPD::Song::getDate
129 || st
.function() == &MPD::Song::getLength
)
130 tags
.resize(st
.delimiter());
132 tags
= wideShorten(tags
, st
.delimiter());
138 return Result::Missing
;
141 // If all Empty -> Empty, if any Ok -> continue with Ok, if any Missing ->
143 Result
operator()(const Group
<CharT
> &group
)
145 auto visit
= [this, &group
] {
146 Result result
= Result::Empty
;
147 for (const auto &ex
: group
.base())
149 result
+= boost::apply_visitor(*this, ex
);
150 if (result
== Result::Missing
)
152 result
= Result::Empty
;
160 Result result
= visit();
162 if (!m_no_output
&& result
== Result::Ok
)
167 // If all Empty or Missing -> Empty, if any Ok -> stop with Ok.
168 Result
operator()(const FirstOf
<CharT
> &first_of
)
170 for (const auto &ex
: first_of
.base())
172 if (boost::apply_visitor(*this, ex
) == Result::Ok
)
175 return Result::Empty
;
179 // generic version for streams (buffers, menus)
180 template <typename ValueT
, typename OutputStreamT
>
182 static void exec(OutputStreamT
&os
, const ValueT
&value
, const SongTag
*) {
187 // specialization for strings (input/output)
188 template <typename SomeCharT
, typename OtherCharT
>
189 struct output_
<std::basic_string
<SomeCharT
>, std::basic_string
<OtherCharT
>> {
190 typedef std::basic_string
<SomeCharT
> SomeString
;
191 typedef std::basic_string
<OtherCharT
> OtherString
;
193 // compile only if string types are the same
194 static typename
std::enable_if
<
195 std::is_same
<SomeString
, OtherString
>::value
,
197 >::type
exec(SomeString
&result
, const OtherString
&s
, const SongTag
*) {
201 // When writing to a string, we should ignore all other properties. If this
202 // code is reached, throw an exception.
203 template <typename ValueT
, typename SomeCharT
>
204 struct output_
<ValueT
, std::basic_string
<SomeCharT
>> {
205 static void exec(std::basic_string
<CharT
> &, const ValueT
&, const SongTag
*) {
206 throw std::logic_error("non-string property can't be appended to the string");
210 // Specialization for TagVector.
211 template <typename SomeCharT
, typename OtherCharT
>
212 struct output_
<std::basic_string
<SomeCharT
>, TagVector
<OtherCharT
> > {
213 // Compile only if string types are the same.
214 static typename
std::enable_if
<
215 std::is_same
<SomeCharT
, OtherCharT
>::value
,
217 >::type
exec(TagVector
<OtherCharT
> &acc
,
218 const std::basic_string
<SomeCharT
> &s
, const SongTag
*st
) {
220 acc
.emplace_back(*st
, s
);
222 acc
.emplace_back(boost::none
, s
);
225 // When extracting tags from a song all the other properties should be
226 // ignored. If that's not the case, throw an exception.
227 template <typename ValueT
, typename SomeCharT
>
228 struct output_
<ValueT
, TagVector
<SomeCharT
> > {
229 static void exec(TagVector
<SomeCharT
> &, const ValueT
&, const SongTag
*) {
230 throw std::logic_error("Non-string property can't be inserted into the TagVector");
234 template <typename ValueT
>
235 void output(const ValueT
&value
, const SongTag
*st
= nullptr) const
239 if (m_output_switched
&& m_second_os
!= nullptr)
240 output_
<ValueT
, SecondOutputT
>::exec(*m_second_os
, value
, st
);
242 output_
<ValueT
, OutputT
>::exec(m_output
, value
, st
);
247 const MPD::Song
*m_song
;
249 bool m_output_switched
;
250 SecondOutputT
*m_second_os
;
252 unsigned m_no_output
;
253 const unsigned m_flags
;
256 template <typename CharT
, typename VisitorT
>
257 void visit(VisitorT
&visitor
, const AST
<CharT
> &ast
)
259 for (const auto &ex
: ast
.base())
260 boost::apply_visitor(visitor
, ex
);
263 template <typename CharT
, typename ItemT
>
264 void print(const AST
<CharT
> &ast
, NC::Menu
<ItemT
> &menu
, const MPD::Song
*song
,
265 NC::BasicBuffer
<CharT
> *buffer
, const unsigned flags
)
267 Printer
<CharT
, NC::Menu
<ItemT
>, NC::Buffer
> printer(menu
, song
, buffer
, flags
);
271 template <typename CharT
>
272 void print(const AST
<CharT
> &ast
, NC::BasicBuffer
<CharT
> &buffer
,
273 const MPD::Song
*song
, const unsigned flags
)
275 Printer
<CharT
, NC::BasicBuffer
<CharT
>> printer(buffer
, song
, &buffer
, flags
);
279 template <typename CharT
>
280 std::basic_string
<CharT
> stringify(const AST
<CharT
> &ast
, const MPD::Song
*song
)
282 std::basic_string
<CharT
> result
;
283 Printer
<CharT
, std::basic_string
<CharT
>> printer(result
, song
, &result
, Flags::Tag
);
288 template <typename CharT
>
289 TagVector
<CharT
> flatten(const AST
<CharT
> &ast
, const MPD::Song
&song
)
291 TagVector
<CharT
> result
;
292 Printer
<CharT
, TagVector
<CharT
>> printer(result
, &song
, &result
, Flags::Tag
);
299 #endif // NCMPCPP_HAVE_FORMAT__IMPL_H