├── .github
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── CMake
├── CMakeLists.googletest-download.txt
├── CMakeLists.googletest.txt
└── uninstall.cmake
├── CMakeLists.txt
├── LICENSE.md
├── README.md
├── TODO.md
├── config
├── feeds.conf
├── keys.conf
└── neix.conf
├── doc
└── neix.1
├── include
├── application
│ ├── Application.h
│ └── ApplicationWindow.h
├── config.h
├── config
│ ├── ConfigReader.h
│ └── opml.h
├── database
│ ├── Database.h
│ └── schema.h
├── feed
│ ├── FeedLoader.h
│ └── Feeds.h
├── helper
│ ├── TextConverter.h
│ └── helper.h
├── parser
│ ├── FactoryParser.h
│ ├── Parser.h
│ ├── ParserAtom.h
│ └── ParserRSS.h
└── rapidxml
│ ├── license.txt
│ ├── rapidxml.hpp
│ ├── rapidxml_iterators.hpp
│ ├── rapidxml_print.hpp
│ └── rapidxml_utils.hpp
├── screenshots
├── .gitkeep
├── neix-v0.1.3.gif
├── screenshot-1.png
├── screenshot-2.png
├── screenshot-3.png
└── screenshot-4.png
├── src
├── application
│ ├── Application.cpp
│ └── ApplicationWindow.cpp
├── config
│ ├── ConfigReader.cpp
│ └── opml.cpp
├── feed
│ ├── FeedLoader.cpp
│ └── Feeds.cpp
├── helper
│ ├── TextConverter.cpp
│ └── helper.cpp
├── main.cpp
└── parser
│ ├── FactoryParser.cpp
│ ├── Parser.cpp
│ ├── ParserAtom.cpp
│ └── ParserRSS.cpp
└── test
├── CMakeLists.txt
├── application
└── ApplicationWindow.cpp
├── assets
├── atom.xml
├── importFeeds.conf
├── opml.xml
├── reddit.xml
├── rss0.91.xml
├── rss0.92.xml
├── rss2.0.xml
├── testFeeds.conf
└── testNeix.conf
├── config
├── ConfigReader.cpp
└── opml.cpp
├── feed
├── FeedLoader.cpp
└── Feeds.cpp
├── helper
├── TextConverter.cpp
└── helper.cpp
├── main.cpp
└── parser
└── Parser.cpp
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at thomasschwarz96@web.de. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # :memo: Contributing
2 | I am glad that you are reading this file. Seriously! Because that means you are interested to helping on improve **neix**. :confetti_ball:
3 | I appreciate every single help. You are sincerely welcome!
4 |
5 | I will try to explain it as best as possible.
6 |
7 | ## Bug reporting
8 | If you found a bug make sure that there is no similar issue reported.
9 | There is no appropriate issue? Then feel free to create a new one.
10 | Please take the right ISSUE_TEMPLATE.
11 |
12 | If there is a issue with a lack of informations, feel free to add your comment or your constellation.
13 | If you got an idea how to solve an bug, please create a comment with your idea!
14 |
15 | ## Issues / Bugs
16 | If you want to fix an issue, make sure that there is nobody working on the same one.
17 | On big issues, ask someone if you can help.
18 |
19 | ## New feature
20 | You have a nice idea or a cool feature?
21 | For major changes, please open an issue first to discuss what you would like to change and how you would do it.
22 |
23 | Please make sure to update tests as appropriate.
24 |
25 | # Code
26 | It is important to apply the principles of clean code.
27 | If you got some questions, let me know. Just write a comment on the issue and i will help as soon as possible.
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "[BUG] "
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Press key '....'
17 | 3. See error
18 |
19 | **Expected behavior**
20 | A clear and concise description of what you expected to happen.
21 |
22 | **Screenshots**
23 | If applicable, add screenshots to help explain your problem.
24 |
25 | **Desktop (please complete the following information):**
26 | - OS: [e.g. Debian 10]
27 | - Version [e.g. 2.1]
28 |
29 | **Additional context**
30 | Add any other context about the problem here.
31 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "[FEATURE] "
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Object files
5 | *.o
6 | *.ko
7 | *.obj
8 | *.elf
9 |
10 | # Linker output
11 | *.ilk
12 | *.map
13 | *.exp
14 |
15 | # Precompiled Headers
16 | *.gch
17 | *.pch
18 |
19 | # Libraries
20 | *.lib
21 | *.a
22 | *.la
23 | *.lo
24 |
25 | # Shared objects (inc. Windows DLLs)
26 | *.dll
27 | *.so
28 | *.so.*
29 | *.dylib
30 |
31 | # Executables
32 | *.exe
33 | *.out
34 | *.app
35 | *.i*86
36 | *.x86_64
37 | *.hex
38 |
39 | # Debug files
40 | *.dSYM/
41 | *.su
42 | *.idb
43 | *.pdb
44 |
45 | # Kernel Module Compile Results
46 | *.mod*
47 | *.cmd
48 | .tmp_versions/
49 | modules.order
50 | Module.symvers
51 | Mkfile.old
52 | dkms.conf
53 |
54 | # IDE files
55 | .idea
56 |
57 | # Project settings
58 | *.cmake
59 | *.cbp
60 | googletest*
61 | CMakeFiles
62 | CMakeCache.txt
63 | install_manifest.txt
64 | Makefile
65 | bin
66 | Testing
67 |
--------------------------------------------------------------------------------
/CMake/CMakeLists.googletest-download.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.13)
2 | project(googletest NONE)
3 |
4 | include(ExternalProject)
5 | ExternalProject_Add(googletest
6 | GIT_REPOSITORY https://github.com/google/googletest.git
7 | GIT_TAG release-1.8.1
8 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
9 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
10 | CONFIGURE_COMMAND ""
11 | BUILD_COMMAND ""
12 | INSTALL_COMMAND ""
13 | TEST_COMMAND ""
14 | )
--------------------------------------------------------------------------------
/CMake/CMakeLists.googletest.txt:
--------------------------------------------------------------------------------
1 | # Download and unpack googletest at configure time
2 | configure_file(CMake/CMakeLists.googletest-download.txt googletest/CMakeLists.txt)
3 | execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
4 | RESULT_VARIABLE result
5 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest)
6 | if(result)
7 | message(FATAL_ERROR "CMake step for googletest failed: ${result}")
8 | endif()
9 | execute_process(COMMAND ${CMAKE_COMMAND} --build .
10 | RESULT_VARIABLE result
11 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest)
12 | if(result)
13 | message(FATAL_ERROR "Build step for googletest failed: ${result}")
14 | endif()
15 |
16 | # Prevent overriding the parent project's compiler/linker
17 | # settings on Windows
18 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
19 |
20 | # Add googletest directly to our build. This defines
21 | # the gtest and gtest_main targets.
22 | add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
23 | ${CMAKE_CURRENT_BINARY_DIR}/googletest-build
24 | EXCLUDE_FROM_ALL)
25 |
26 | # The gtest/gtest_main targets carry header search path
27 | # dependencies automatically when using CMake 2.8.11 or
28 | # later. Otherwise we have to add them here ourselves.
29 | if (CMAKE_VERSION VERSION_LESS 2.8.11)
30 | include_directories("${gtest_SOURCE_DIR}/include")
31 | endif()
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/CMake/uninstall.cmake:
--------------------------------------------------------------------------------
1 | set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
2 |
3 | if(NOT EXISTS ${MANIFEST})
4 | message(FATAL_ERROR "Cannot find install manifest: '${MANIFEST}'")
5 | endif()
6 |
7 | file(STRINGS ${MANIFEST} files)
8 | foreach(file ${files})
9 | if(EXISTS ${file})
10 | message(STATUS "Removing file: '${file}'")
11 |
12 | exec_program(
13 | ${CMAKE_COMMAND} ARGS "-E remove ${file}"
14 | OUTPUT_VARIABLE stdout
15 | RETURN_VALUE result
16 | )
17 |
18 | if(NOT "${result}" STREQUAL 0)
19 | message(FATAL_ERROR "Failed to remove file: '${file}'.")
20 | endif()
21 | else()
22 | MESSAGE(STATUS "File '${file}' does not exist.")
23 | endif()
24 | endforeach(file)
25 |
26 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.12)
2 | project(neix)
3 |
4 | include(GNUInstallDirs)
5 |
6 | # Check if 'curl' is installed
7 | find_package(CURL REQUIRED)
8 | include_directories(${CURL_INCLUDE_DIR})
9 |
10 | # Check if 'ncurses' is installed
11 | SET(CURSES_NEED_NCURSES TRUE)
12 | SET(CURSES_NEED_WIDE TRUE)
13 | find_package(Curses)
14 | if (NOT CURSES_FOUND)
15 | MESSAGE(STATUS "ncursesw not found. Include only ncurses.")
16 | SET(CURSES_NEED_WIDE FALSE)
17 | find_package(Curses REQUIRED)
18 | endif()
19 | include_directories(${CURSES_INCLUDE_DIRS})
20 |
21 | SET(CURSES_NEED_NCURSES TRUE)
22 | find_package(Curses REQUIRED)
23 | include_directories(${CURSES_INCLUDE_DIRS})
24 |
25 | # Prepare filesystem for installation
26 | file(MAKE_DIRECTORY $ENV{HOME}/.config/neix/)
27 |
28 | # Check for main config file
29 | if(NOT EXISTS "$ENV{HOME}/.config/neix/neix.conf")
30 | configure_file(./config/neix.conf $ENV{HOME}/.config/neix/neix.conf)
31 | endif()
32 |
33 | # Check for feed config file
34 | if(NOT EXISTS "$ENV{HOME}/.config/neix/feeds.conf")
35 | configure_file(./config/feeds.conf $ENV{HOME}/.config/neix/feeds.conf)
36 | endif()
37 |
38 | # Version
39 | set(neixVersion "0.1.5")
40 | add_compile_definitions(VERSION="v${neixVersion}")
41 |
42 | # User Agent for CURL
43 | set(neixUserAgent "neix/${neixVersion}")
44 | add_compile_definitions(NEIX_USER_AGENT="${neixUserAgent}")
45 |
46 | # Add default config URL's
47 | add_compile_definitions(DEFAULT_MAIN_CONFIG="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/neix/neix.conf")
48 | add_compile_definitions(DEFAULT_FEEDS_CONFIG="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/neix/feeds.conf")
49 |
50 | # Path for main neix config file
51 | set(MainConfigPath "$ENV{HOME}/.config/neix/neix.conf")
52 | add_compile_definitions(MAIN_CONFIG_PATH="${MainConfigPath}")
53 |
54 | # Path for feed config file
55 | set(FeedConfigPath "$ENV{HOME}/.config/neix/feeds.conf")
56 | add_compile_definitions(FEED_CONFIG_PATH="${FeedConfigPath}")
57 |
58 | set(CMAKE_CXX_STANDARD 11)
59 | set(CMAKE_CXX_EXTENSIONS OFF)
60 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
61 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin/library)
62 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
63 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
64 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
65 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
66 |
67 | include_directories(
68 | ${PROJECT_SOURCE_DIR}/include
69 | )
70 |
71 | FILE(GLOB main ${PROJECT_SOURCE_DIR}/src/*.cpp)
72 | FILE(GLOB application ${PROJECT_SOURCE_DIR}/src/application/*.cpp)
73 | FILE(GLOB feed ${PROJECT_SOURCE_DIR}/src/feed/*.cpp)
74 | FILE(GLOB parser ${PROJECT_SOURCE_DIR}/src/parser/*.cpp)
75 | FILE(GLOB config ${PROJECT_SOURCE_DIR}/src/config/*.cpp)
76 | FILE(GLOB helper ${PROJECT_SOURCE_DIR}/src/helper/*.cpp)
77 |
78 | add_library(neixApplication STATIC ${application})
79 | add_library(neixFeed STATIC ${feed})
80 | add_library(neixParser STATIC ${parser})
81 | add_library(neixConfig STATIC ${config})
82 | add_library(neixHelper STATIC ${helper})
83 |
84 | add_executable(neix ${main})
85 | target_link_libraries(neix neixApplication ${CURSES_LIBRARIES})
86 | target_link_libraries(neix neixFeed ${CURL_LIBRARY})
87 | target_link_libraries(neix neixParser)
88 | target_link_libraries(neix neixConfig)
89 | target_link_libraries(neix neixHelper)
90 |
91 | option(ENABLE-TESTS "Enables test suite" OFF)
92 | if(ENABLE-TESTS MATCHES ON)
93 | # Download and configure google test
94 | include(CMake/CMakeLists.googletest.txt)
95 |
96 | add_subdirectory(test)
97 | endif()
98 |
99 | # Install definitons
100 | install(TARGETS neix RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
101 | install(FILES ./doc/neix.1 DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man1")
102 |
103 | install(FILES ./config/neix.conf DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/neix")
104 | install(FILES ./config/feeds.conf DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/neix")
105 |
106 | # Uninstall definitins
107 | add_custom_target(uninstall
108 | "${CMAKE_COMMAND}" -P "CMake/uninstall.cmake"
109 | )
110 |
111 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 | neix - It is an terminal feed reader for all common RSS/Atom feeds on the web out there.
635 | It will protect your privacy with a nice looking TUI and with an nice performance.
636 | Copyright (C) 2020 Tom Schwarz
637 |
638 | This program is free software: you can redistribute it and/or modify
639 | it under the terms of the GNU General Public License as published by
640 | the Free Software Foundation, either version 3 of the License, or
641 | (at your option) any later version.
642 |
643 | This program is distributed in the hope that it will be useful,
644 | but WITHOUT ANY WARRANTY; without even the implied warranty of
645 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
646 | GNU General Public License for more details.
647 |
648 | You should have received a copy of the GNU General Public License
649 | along with this program. If not, see .
650 |
651 | Also add information on how to contact you by electronic and paper mail.
652 |
653 | If the program does terminal interaction, make it output a short
654 | notice like this when it starts in an interactive mode:
655 |
656 | neix Copyright (C) 2020 Tom Schwarz
657 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
658 | This is free software, and you are welcome to redistribute it
659 | under certain conditions; type `show c' for details.
660 |
661 | The hypothetical commands `show w' and `show c' should show the appropriate
662 | parts of the General Public License. Of course, your program's commands
663 | might be different; for a GUI interface, you would use an "about box".
664 |
665 | You should also get your employer (if you work as a programmer) or school,
666 | if any, to sign a "copyright disclaimer" for the program, if necessary.
667 | For more information on this, and how to apply and follow the GNU GPL, see
668 | .
669 |
670 | The GNU General Public License does not permit incorporating your program
671 | into proprietary programs. If your program is a subroutine library, you
672 | may consider it more useful to permit linking proprietary applications with
673 | the library. If this is what you want to do, use the GNU Lesser General
674 | Public License instead of this License. But first, please read
675 | .
676 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # neix - a news reader for your terminal
2 | 
3 | 
4 | 
5 | 
6 |
7 | **neix** is a simple, **work in progress** terminal feed reader for all common RSS/Atom feeds on the web out there.
8 | So you can read your news without advertisments or other annoying stuff. Just the informations you need.
9 | You can import your existing collection of feeds from an OPML file or just configure them manually.
10 | You also have the ability to render the text with w3m, elinks or which program you want.
11 | How to configure neix, take a look into the [configuration](#wrench-configuration) section.
12 | You got the full control of your news you want to read!
13 |
14 | 
15 |
16 | ## :page_facing_up: Table of Contents
17 | - [Installation](#pager-installation)
18 | - [Manual installation](#pager-manual-installation)
19 | - [Requirements](#bookmark_tabs-requirements)
20 | - [Packaging](#computer-packaging)
21 | - [Uninstall](#pager-uninstall)
22 | - [Unit tests](#heavy_check_mark-unit-tests)
23 | - [Usage](#clipboard-usage)
24 | - [Command line options](#clipboard-command-line-options)
25 | - [Configuration](#wrench-configuration)
26 | - [neix.conf](#nut_and_bolt-neixconf)
27 | - [feeds.conf](#nut_and_bolt-feedsconf)
28 | - [Contributing](#memo-contributing)
29 | - [TODO / Roadmap](https://github.com/tomschwarz/neix/blob/master/TODO.md)
30 | - [Issues / Bugs](https://github.com/tomschwarz/neix/issues)
31 | - [Libaries in usage](#books-libaries-in-usage)
32 | - [License](#scroll-license)
33 | - [Screenshots](#camera-screenshots)
34 |
35 | ## :pager: Installation
36 | Before you can install **neix** make sure you have installed all [required](#bookmark_tabs-requirements) packages.
37 | After the successful installation you have to configure the **feeds.conf**
38 | file with the feeds you want to read.
39 | [Here](#nut_and_bolt-feedsconf) you can see the proper format.
40 |
41 | ### :pager: Manual installation
42 | Follow the steps below for installing:
43 | ```bash
44 | $ git clone https://github.com/tomschwarz/neix.git
45 | $ cd neix
46 | $ cmake . # to enable unit-tests: cmake -DENABLE-TESTS=ON
47 | $ make
48 | $ sudo make install
49 | ```
50 |
51 | ### :bookmark_tabs: Requirements
52 | - [cmake (version 3.12 or newer)](https://cmake.org/download/)
53 | - [libcurl (version 7.64.0 or newer)](http://curl.haxx.se/download.html)
54 | - [ncurses (version 5 or newer)](https://invisible-island.net/ncurses/#downloads)
55 |
56 | ### :computer: Packaging
57 | **neix** is available packaged for the following package manager/operating systems:
58 |
59 | #### AUR [](https://aur.archlinux.org/packages/neix/)
60 | ```bash
61 | $ git clone https://aur.archlinux.org/neix.git
62 | $ cd neix
63 | $ makepkg -si
64 | ```
65 |
66 | #### Zypper [](https://build.opensuse.org/package/show/network:utilities/neix)
67 | ```bash
68 | $ zypper install neix
69 | ```
70 |
71 | #### Pkgin [](https://ftp.netbsd.org/pub/pkgsrc/current/pkgsrc/news/neix/README.html)
72 | ```bash
73 | $ pkgin install neix
74 | ```
75 |
76 | ---
77 |
78 | For some custom build packages or scripts see the [packages](https://github.com/tomschwarz/neix/wiki/Install-packages) section on the wiki.
79 |
80 | ## :pager: Uninstall
81 | Follow the steps below for uninstalling:
82 | ```bash
83 | $ cd neix # should be the same directory where the repository was cloned into
84 | $ sudo make uninstall
85 | ```
86 |
87 | If there is an error during the uninstall process or you don't have the
88 | directory anymore following the steps below:
89 | ```bash
90 | $ sudo updatedb
91 | $ locate neix # $ locate neix | grep /usr - if the output is to large
92 | $ sudo rm {PATH}/neix # where {PATH} is the full path to the binary
93 | ```
94 |
95 | ## :heavy_check_mark: Unit tests
96 | Follow the steps below for unit testing after the installation guide:
97 | ```bash
98 | $ ./bin/tests
99 | ```
100 | **Hint:** you have to be in the main directory of neix!
101 |
102 | To run only a specific test follow the steps below:
103 | ```bash
104 | $ ./bin/tests --gtest_filter=
105 | ```
106 |
107 | To list which tests are available follow the steps below:
108 | ```bash
109 | $ ./bin/tests --gtest_list_tests
110 | ```
111 |
112 | For more informations see [GoogleTest](https://github.com/google/googletest).
113 |
114 | ## :clipboard: Usage
115 | ```bash
116 | $ neix
117 | ```
118 | If **neix** is completely launched you got the following key's to navigate:
119 | | Key | Function |
120 | |---------------------------------|--------------------------------------------------------------------------------------------------------|
121 | | q | Close the current opened article or quit **neix** when you on the not reading an article. |
122 | | ENTER | Open the selected article to read. |
123 | | o | Open the current article in the browser (or with the programm you configured in the main config file). |
124 | | j | Select the next article in the current feed list. |
125 | | k | Select the previous article in the current feed list. |
126 | | Shift + j | Select the next feed of the loaded feed list. |
127 | | Shift + k | Select the previous feed of the loaded feed list. |
128 |
129 | ---
130 |
131 | ### :clipboard: Command line options
132 | **neix** has some command line options you can use.
133 | See below the available options:
134 |
135 | | Option | Argument | Description |
136 | |---------------|--------------|--------------------------------------------------------------------------------------------------|
137 | | -v | `-` | Prints the installed version of **neix** and exits. |
138 | | -i | `` | Import feeds of given OPML file and exits. Path can be absolute or relative. |
139 | | -e | `` | Export feeds to given file or path. Creates an OPML 2.0 file. Path can be absolute or relative. |
140 | | -f | `` | Use a custom feed configuration file. Have to be located in the default neix config folder. |
141 |
142 | Usage of option `-v`:
143 | ```bash
144 | $ neix -v
145 | ```
146 |
147 | Usage of option `-i`:
148 | ```bash
149 | $ neix -i ~/Downloads/import.xml
150 | ```
151 |
152 | Usage of option `-e`:
153 | ```bash
154 | $ neix -e ~/Downloads/export.xml
155 | ```
156 |
157 | Usage of option `-f`:
158 | ```bash
159 | # Location: ~/.config/neix/custom-feeds.conf
160 | $ neix -f custom-feeds.conf
161 | ```
162 |
163 | ---
164 |
165 | For more informations see the man-page:
166 | ```bash
167 | $ man neix
168 | ```
169 |
170 | ## :wrench: Configuration
171 | Default directory of the config files: **~/.config/neix/**
172 | During the installtion process, **neix** create's the default directory with the needed configuration files.
173 |
174 | **neix** needs two configuration files. One for itself and one for the feeds which should be loaded.
175 | | File | Description |
176 | |------------|----------------------------------------------------------------------------------------|
177 | | neix.conf | This is the main configuration. It include's the date format, locale and more options. |
178 | | feeds.conf | This is the feed list. An entry represents a single news feed. |
179 |
180 | ### :nut_and_bolt: neix.conf
181 | This is the main config file of **neix**.
182 | | Option | Value |
183 | |-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
184 | | dateFormat | String which represents the format for the feed date. Here are all possible [formats](http://www.cplusplus.com/reference/iomanip/put_time/). [REQUIRED] |
185 | | locale | Here you can set the locale for your language ([see here](http://cplusplus.com/reference/clocale/setlocale/)). Run **locale -a** to see all locales you got installed. [REQUIRED] |
186 | | openCommand | Here you can set which programm should be used to open the article link. Default is **xdg-open**. You can use what you want. [REQUIRED] |
187 | | renderText | You can set here how the text should be formatted. Default is **w3m -dump -T text/html**. You can use **elinks** or others. [OPTIONAL] |
188 |
189 | ### :nut_and_bolt: feeds.conf
190 | This file contains the list of feeds you want to read.
191 | This is the required format of an single entry (every entry should be in a seperate line):
192 | ```bash
193 | TITLE = PROTOCOL://[username[:password]@]DOMAIN.TOP-LEVEL-DOMAIN[/DIRECTORIES[/FILE]]
194 | ```
195 |
196 | ## :memo: Contributing
197 | If you want to contribute check the [CONTRIBUTING.md](https://github.com/tomschwarz/neix/blob/master/.github/CONTRIBUTING.md)
198 |
199 | ## :books: Libaries in usage
200 | - [rapidXML](http://rapidxml.sourceforge.net/) is used for XML parsing
201 | - [GoogleTest](https://github.com/google/googletest) is used for TDD
202 |
203 | ## :scroll: License
204 | [GNU GPLv3](https://choosealicense.com/licenses/gpl-3.0/) © [Tom Schwarz](https://github.com/tomschwarz)
205 |
206 | ## :camera: Screenshots
207 | 
208 | 
209 | 
210 | 
211 |
212 | ----
213 |
214 | #### Free Software Foundation
215 |
216 |
217 |
218 | I'm a member of the Free Software Foundation. Without GNU/Linux and all the great work from people all over the world producing free software, this project would not have been possible.
219 |
220 | Consider joining the FSF, [here is why](https://my.fsf.org/join?referrer=5002414).
221 |
222 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | # :page_with_curl: TODO / Roadmap
2 | * [ ] Add SQLite (save read/unread and more)
3 | * [ ] Mixed list of feeds, sorted by date
4 | * [ ] List feeds by tags, sorted by date
5 | * [ ] Add commands
6 | * [ ] Add interface
7 | * [ ] Add custom commands
8 | * [ ] Add tags to feeds
9 | * [ ] Add search
10 | * [ ] Add native HTML rendering
11 | * [x] Add rendering for content
12 | * [x] Load feeds with correct order
13 | * [ ] Add variables for main config entries
14 | * [x] Add OPML support
15 | * [x] OPML Import
16 | * [x] OPML Export
17 | * [x] Add GIF to README
18 | * [x] Add install dependencies to README
19 |
20 | ## :chart_with_downwards_trend: Low priority
21 | * [x] Add man-page on install
22 | * [ ] Add logging ([spdlog](https://github.com/gabime/spdlog))
23 | * [x] Optimize for termux
24 |
25 | ## :question: Maybe
26 | * [ ] ?? Change to libxml++ ??
27 |
28 |
29 |
--------------------------------------------------------------------------------
/config/feeds.conf:
--------------------------------------------------------------------------------
1 | #
2 | # neix main "feeds" configuration
3 | # ===============================
4 | #
5 | # Example:
6 | # TITLE = PROTOCOL://[username[:password]@]DOMAIN.TOP-LEVEL-DOMAIN
7 | [neix] commits=https://github.com/tomschwarz/neix/commits/master.atom
8 | [neix] releases=https://github.com/tomschwarz/neix/releases.atom
9 |
--------------------------------------------------------------------------------
/config/keys.conf:
--------------------------------------------------------------------------------
1 | #
2 | # neix main "keys" configuration
3 | # ===============================
4 | # Allowed values are the "printable" ASCII characters.
5 | # You can find a list here:
6 | # - https://en.wikipedia.org/wiki/ASCII#Printable_characters
7 | # ===============================
8 |
9 | #
10 | # Default key: "ENTER"
11 | # Function: read article
12 | keyReadArticle=\n
13 |
14 | #
15 | # Default key: "j"
16 | # Function: next article
17 | keyNextArticle=j
18 |
19 | #
20 | # Default key: "k"
21 | # Function: previous article
22 | keyPreviousArticle=k
23 |
24 | #
25 | # Default key: "J"
26 | # Function: next feed
27 | keyNextFeed=J
28 |
29 | #
30 | # Default key: "K"
31 | # Function: previous feed
32 | keyPreviousFeed=K
33 |
34 | #
35 | # Default key: "o"
36 | # Function: open article in browser
37 | keyOpenArticle=o
38 |
39 | #
40 | # Default key: "q"
41 | # Function: quit neix / close article
42 | keyQuitAndClose=q
43 |
--------------------------------------------------------------------------------
/config/neix.conf:
--------------------------------------------------------------------------------
1 | #
2 | # neix main configuration
3 | # =======================
4 |
5 | #
6 | # Determines the date format for the TUI
7 | # Default: %d.%m.%Y %H:%M
8 | dateFormat=%d.%m.%Y %H:%M
9 |
10 | #
11 | # Indicates which locale should be used
12 | # Default: de_DE.UTF-8 UTF-8
13 | locale=de_DE.UTF-8 UTF-8
14 |
15 | #
16 | # Determines how to open article link
17 | # Default: xdg-open
18 | openCommand=xdg-open
19 |
20 | #
21 | # Determines how to render the article text
22 | # Default: ""
23 | # Example: renderText=w3m -dump -T text/html
24 | #renderText=
25 |
--------------------------------------------------------------------------------
/doc/neix.1:
--------------------------------------------------------------------------------
1 | .TH neix 1 "30th April 2021" "v0.1.5" "neix man page"
2 |
3 | .SH NAME
4 | .B neix
5 | - RSS/Atom feed reader for your terminal.
6 |
7 | .SH SYNOPSIS
8 | .B neix
9 | is an terminal feed reader for all common RSS/Atom feeds on the web out there.
10 |
11 | .SH DESCRIPTION
12 | .B neix
13 | is an terminal feed reader for all common RSS/Atom feeds on the web out there.
14 | It is free/libre software which protects your freedom.
15 | You got the full control of your news you want to read!
16 |
17 | .SH OPTIONS
18 | .TP
19 | .B -v
20 | Prints the installed version of *neix* and exits.
21 |
22 | .TP
23 | .B -i
24 | Import feeds of given OPML file and exits.
25 | Path can be absolute or relative. The OPML file has to be a valid!
26 | See OPML specification: http://dev.opml.org/spec2.html
27 |
28 | .TP
29 | .B -e
30 | Export feeds to given file or path.
31 | Path can be absolute or relative.
32 | Creates and OPML file in version 2.0.
33 | See OPML specification: http://dev.opml.org/spec2.html
34 |
35 | .TP
36 | .B -f
37 | Use a custom feed configuration file. Have to be the same format as the default feed config file.
38 | Must be located in the default neix config folder: ~/.config/neix/
39 |
40 | .SH RUNTIME COMMANDS
41 | .TP
42 | .B q
43 | Close the current opened article or quit neix when you on the not reading an article.
44 |
45 | .TP
46 | .B ENTER
47 | Open the selected article to read.
48 |
49 | .TP
50 | .B o
51 | Open the current article in the browser (or with the programm you configured in the main config file).
52 |
53 | .TP
54 | .B j
55 | Select the next article in the current feed list.
56 |
57 | .TP
58 | .B k
59 | Select the previous article in the current feed list.
60 |
61 | .TP
62 | .B Shift + j
63 | Select the next feed of the loaded feed list.
64 |
65 | .TP
66 | .B Shift + k
67 | Select the previous feed of the loaded feed list.
68 |
69 | .SH FILES
70 | .TP
71 | .I
72 | ~/.config/neix/neix.conf
73 | This is the main config file of neix. Below you can see all available options.
74 |
75 | .
76 | .RS 1.2i
77 | .TS
78 | tab(@), left, box;
79 | l | l
80 | lB | l.
81 | OPTION@Value
82 | _
83 | dateFormat@String which represents the format for the feed date.
84 | locale@Here you can set the locale for your language.
85 | openCommand@Here you can set which program should be used to open the article link.
86 | renderText@You can set how the text should be formatted.
87 | @`$article_width` will be replaced with the article frame width,
88 | @which can be useful to limit width of dumped output [OPTIONAL]
89 | .TE
90 | .RE
91 |
92 | .TP
93 | .I
94 | ~/.config/neix/feeds.conf
95 | This file contains the list of feeds you want to read.
96 | Below you can see the required format of an single entry.
97 |
98 | .B
99 | TITLE = PROTOCOL://[username[:password]@]DOMAIN.TOP-LEVEL-DOMAIN[/DIRECTORIES[/FILE]]
100 |
101 | .SH AUTHORS
102 | Maintained by Tom Schwarz, who is assisted by
103 | other open source contributors. For more informations about
104 | .B neix
105 | development see https://github.com/tomschwarz/neix.
106 |
107 | .SH SEE ALSO
108 | .B ncurses(1),
109 | .B curl(1)
110 |
--------------------------------------------------------------------------------
/include/application/Application.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Terminal UI class.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #ifndef neix_APPLICATION_H
13 | #define neix_APPLICATION_H
14 |
15 | #include
16 | #include
17 | #include "application/ApplicationWindow.h"
18 | #include "feed/Feeds.h"
19 |
20 | using namespace std;
21 | namespace neix
22 | {
23 | class Application
24 | {
25 | public:
26 | Application();
27 | ~Application();
28 |
29 | void show();
30 | void fillWindowsWithContent();
31 | void printWindows();
32 | void resize();
33 |
34 | int increaseChoice(int new_choice, int count);
35 | int decreaseChoice(int new_choice, int count);
36 |
37 | string openCommand;
38 | string renderCommand;
39 |
40 | private:
41 | ApplicationWindow fw;
42 | ApplicationWindow aw;
43 | ApplicationWindow rw;
44 |
45 | bool reading;
46 | int choice;
47 | int articleChoice;
48 | int quit;
49 | int c;
50 |
51 | int feedWindowWidth;
52 | int feedWindowHeight;
53 | int articleWindowWidth;
54 | int articleWindowHeight;
55 |
56 | void initChoices();
57 | void printVersion();
58 | void printControlHints();
59 | void createFeedWindow();
60 | void createArticleWindow();
61 | void createReadWindow();
62 |
63 | void printFeedsInWindow();
64 | void printArticlesInWindow();
65 | string printArticleInWindow(struct rssItem *entry);
66 |
67 | void openArticle();
68 | void openArticleLink();
69 | };
70 | }
71 |
72 | #endif //neix_APPLICATION_H
73 |
--------------------------------------------------------------------------------
/include/application/ApplicationWindow.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Application Window class
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | #ifndef neix_APPLICATIONWINDOW_H
17 | #define neix_APPLICATIONWINDOW_H
18 |
19 | using namespace std;
20 | namespace neix
21 | {
22 | class ApplicationWindow
23 | {
24 | public:
25 | ApplicationWindow();
26 | ~ApplicationWindow();
27 |
28 | bool enableHighlight;
29 | bool scrollAlways;
30 |
31 | void show();
32 | void hide();
33 | void update();
34 | void reset();
35 | void resetContent();
36 | void resetHighlight();
37 | void scrollDown();
38 | void scrollUp();
39 |
40 | void setPosition(int y, int x);
41 | void setDimensions(int height, int width);
42 | void pushContent(string c);
43 |
44 | void increaseHighlight();
45 | void decreaseHighlight();
46 |
47 | WINDOW *getWindow();
48 |
49 | protected:
50 | bool created;
51 | int y, x;
52 | int height, width;
53 | int offsetTop;
54 | int highlight;
55 | vector content;
56 | WINDOW *win, *pad;
57 |
58 | bool _create();
59 | void _increaseOffsetTop();
60 | void _decreaseOffsetTop();
61 | void _scrollUpDependingOnContentSize();
62 | void _scrollDownDependingOnContentSize();
63 | void _printWindow();
64 | void _printPad();
65 | void _printContent();
66 | };
67 | }
68 |
69 | #endif //Cneix_APPLICATIONWINDOW_H
--------------------------------------------------------------------------------
/include/config.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Configurations for neix.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #ifndef neix_CONFIG_H
13 | #define neix_CONFIG_H
14 |
15 | #define ENTER 10
16 | #define KEY_J 106
17 | #define KEY_K 107
18 | #define KEY_O 111
19 | #define KEY_Q 113
20 | #define KEY_R 114
21 |
22 | #define KEY_UPPER_J 74
23 | #define KEY_UPPER_K 75
24 |
25 | const char prefix[] = "\033[0;33m[neix]\033[0m ";
26 | extern std::string CUSTOM_FEED_CONFIG;
27 |
28 | #endif //neix_CONFIG_H
29 |
--------------------------------------------------------------------------------
/include/config/ConfigReader.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Config feed reader.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #ifndef neix_CONFIGREADER_H
13 | #define neix_CONFIGREADER_H
14 |
15 | #include
16 |
17 | using namespace std;
18 | namespace neix
19 | {
20 | class ConfigReader
21 | {
22 | public:
23 | ConfigReader(const char* configPath);
24 | ~ConfigReader();
25 |
26 | void parse();
27 | int count();
28 | bool hasEntry(const char* entryName);
29 | string getEntryByName(const char* entryName);
30 | vector> getList();
31 | static ConfigReader create(const char* path);
32 |
33 | protected:
34 | char *path;
35 | vector> list;
36 | };
37 | }
38 |
39 | #endif //neix_CONFIGREADER_H
40 |
--------------------------------------------------------------------------------
/include/config/opml.h:
--------------------------------------------------------------------------------
1 | /**
2 | * OPML import/export.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license GPL-3.0
8 | * @since Version 0.1.2
9 | * @filesource
10 | */
11 |
12 | #ifndef NEIX_OPML_H
13 | #define NEIX_OPML_H
14 |
15 | #include
16 | #include
17 | #include "rapidxml/rapidxml.hpp"
18 |
19 | using namespace std;
20 | using namespace rapidxml;
21 | namespace neix
22 | {
23 | class opml
24 | {
25 | public:
26 | opml();
27 | ~opml();
28 |
29 | void setList(vector> list);
30 | vector> getList();
31 |
32 | void create();
33 | string getContent();
34 | void exportFeeds(const string& path);
35 |
36 | static unsigned int import(const string& importPath,
37 | const string& configPath);
38 |
39 | private:
40 | void _reset();
41 | void _addDeclarationNode();
42 | void _addOpmlBaseNode();
43 | void _addHeadNode();
44 | void _addFeedNodes();
45 |
46 | xml_document<> _doc;
47 | vector> _list;
48 | };
49 | }
50 |
51 | #endif //NEIX_OPML_H
52 |
--------------------------------------------------------------------------------
/include/database/Database.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Database Interface
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.3
9 | * @filesource
10 | */
11 |
12 | #ifndef NEIX_DATABASE_H
13 | #define NEIX_DATABASE_H
14 |
15 | #include
16 |
17 | using namespace std;
18 | namespace neix
19 | {
20 | class Database
21 | {
22 | public:
23 | virtual Database() = default;
24 | virtual ~Database() = default;
25 |
26 | virtual void connect() = 0;
27 | virtual void disconnect() = 0;
28 | virtual bool exists() = 0;
29 | virtual struct rssItem** search(string term) = 0;
30 |
31 | virtual void createSchema() = 0;
32 | virtual void insertFeed(struct rss *feed) = 0;
33 | virtual void insertArticle(struct rssItem *article, int feedID) = 0;
34 | virtual void markArticleAsRead(int articleID) = 0;
35 |
36 | virtual struct rss** getFeeds() = 0;
37 | virtual struct rss* getFeedById(int feedID) = 0;
38 |
39 | virtual struct rssItem** getArticles() = 0;
40 | virtual struct rssItem* getArticleById(int articleID) = 0;
41 | }
42 | }
43 |
44 | #endif //NEIX_DATABASE_H
45 |
--------------------------------------------------------------------------------
/include/database/schema.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Database schema for neix
3 | * > for SQLite
4 | *
5 | * @package neix
6 | * @author Thomas Schwarz
7 | * @copyright Copyright (c) 2020, Thomas Schwarz
8 | * @license -
9 | * @since Version 0.1.3
10 | * @filesource
11 | */
12 |
13 | #ifndef NEIX_SCHEMA_H
14 | #define NEIX_SCHEMA_H
15 |
16 | const char *feeds_schema = "CREATE TABLE FEEDS("\
17 | "ID INT PRIMARY KEY NOT NULL,"\
18 | "TITLE TEXT NOT NULL,"\
19 | "URL TEXT NOT NULL"\
20 | ");";
21 |
22 | const char *article_schema = "CREATE TABLE ARTICLES("\
23 | "ID INT PRIMARY KEY NOT NULL,"\
24 | "FEED_ID INT NOT NULL,"\
25 | "TITLE TEXT NOT NULL,"\
26 | "DESCRIPTION TEXT NOT NULL,"\
27 | "DATE TEXT NOT NULL,"\
28 | "URL TEXT NOT NULL,"\
29 | "FOREIGN KEY(FEED_ID) REFERENCES FEEDS(ID)"\
30 | ");";
31 |
32 | #endif //NEIX_SCHEMA_H
33 |
--------------------------------------------------------------------------------
/include/feed/FeedLoader.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Feed loader class.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #ifndef neix_FEEDLOADER_H
13 | #define neix_FEEDLOADER_H
14 |
15 | #include
16 | #include
17 | #include "Feeds.h"
18 |
19 | struct rawRss
20 | {
21 | char *content;
22 | size_t size;
23 | };
24 |
25 | using namespace std;
26 | namespace neix
27 | {
28 | class FeedLoader
29 | {
30 | public:
31 | FeedLoader();
32 | ~FeedLoader();
33 |
34 | struct rss* createNewFeed(const char* name, const char* link);
35 | bool load(string feedUrl);
36 | struct rawRss getFeed();
37 |
38 | private:
39 | string url;
40 | struct rawRss *feed{};
41 |
42 | void resetFeed();
43 | static size_t curlCalculateMemory(void *content, size_t size, size_t nmemb, void *userp);
44 | bool loadXml();
45 | };
46 | }
47 |
48 | #endif //neix_FEEDLOADER_H
49 |
--------------------------------------------------------------------------------
/include/feed/Feeds.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Feeds singleton class.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #ifndef NEIX_FEEDS_H
13 | #define NEIX_FEEDS_H
14 |
15 | #include
16 | using namespace std;
17 |
18 | struct rssItem
19 | {
20 | char* title;
21 | char* description;
22 | char* date;
23 | char* url;
24 | int read;
25 | };
26 |
27 | struct rss
28 | {
29 | char* title;
30 | char* url;
31 | int articleCount;
32 | int unreadCount;
33 | bool error;
34 | bool loading;
35 | vector items;
36 | };
37 |
38 | namespace neix
39 | {
40 | class Feeds
41 | {
42 | public:
43 | static Feeds* getInstance();
44 | struct rss* getFeed(int index);
45 | struct rssItem* getArticle(int feedIndex, int articleIndex);
46 | int getCount();
47 | char* getFeedLineTitle(int feedIndex, unsigned int length = 0);
48 |
49 | bool validIndex(int index);
50 | bool addFeed(struct rss* newFeed);
51 | bool addArticle(int feedIndex, int articleIndex, struct rssItem* newArticle);
52 |
53 | private:
54 | Feeds();
55 | int count;
56 |
57 | static Feeds* instance;
58 | vector rssFeeds;
59 | };
60 | }
61 |
62 | #endif //NEIX_FEEDS_H
63 |
--------------------------------------------------------------------------------
/include/helper/TextConverter.h:
--------------------------------------------------------------------------------
1 | /**
2 | * TextConverter class.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.3
9 | * @filesource
10 | */
11 |
12 | #ifndef NEIX_TEXTCONVERTER_H
13 | #define NEIX_TEXTCONVERTER_H
14 |
15 | #include
16 | #include "helper/TextConverter.h"
17 |
18 | using namespace std;
19 | namespace neix
20 | {
21 | class TextConverter
22 | {
23 | public:
24 | TextConverter(string t, string c = string(), int a_w = 0);
25 | ~TextConverter();
26 |
27 | string stripHtml();
28 | string execCmd();
29 | bool cmdExecuted;
30 |
31 | private:
32 | string text;
33 | string cmd;
34 | int article_width;
35 | string _buildFullRenderCommand(const string& rawFilePath,
36 | const string& renderedFilePath);
37 | bool _prepareRawText(const string& rawFilePath, const string text);
38 | int _renderText(const string& command);
39 | string _getRenderedText(const string& filePath);
40 | };
41 | }
42 |
43 | #endif //NEIX_TEXTCONVERTER_H
44 |
--------------------------------------------------------------------------------
/include/helper/helper.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Helper functions.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #ifndef neix_HELPER_H
13 | #define neix_HELPER_H
14 |
15 | #include
16 | using namespace std;
17 |
18 | const string WHITESPACE = " \n\r\t\f\v";
19 |
20 | string ltrim(const string& s);
21 | string rtrim(const string& s);
22 | string trim(const string& s);
23 |
24 | string subStrWithEndingDots(const string& s, const unsigned int length);
25 |
26 | // TODO: Put these functions to ConfigReader as static methods
27 | string getConfigHomePath();
28 | string getConfigPathByName(const string& name);
29 | string getMainConfigPath();
30 | string getFeedConfigPath(string configName = "");
31 | bool configFilesExists();
32 | bool copyDefaultConfigFiles();
33 | string replaceString(string str, const string& replace, const string& with);
34 | #endif //neix_HELPER_H
35 |
--------------------------------------------------------------------------------
/include/parser/FactoryParser.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Factory parser class.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #ifndef neix_FACTORYPARSER_H
13 | #define neix_FACTORYPARSER_H
14 |
15 | #include "Parser.h"
16 | #include "feed/FeedLoader.h"
17 |
18 | namespace neix
19 | {
20 | class FactoryParser
21 | {
22 | public:
23 | FactoryParser();
24 | ~FactoryParser();
25 |
26 | static Parser* getInstance(struct rawRss content);
27 | static double getRssVersion(char* content);
28 | };
29 | }
30 |
31 | #endif //neix_FACTORYPARSER_H
32 |
--------------------------------------------------------------------------------
/include/parser/Parser.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Feed parser class.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #ifndef NEIX_PARSER_H
13 | #define NEIX_PARSER_H
14 |
15 | #include
16 | #include "rapidxml/rapidxml.hpp"
17 | #include "feed/FeedLoader.h"
18 |
19 | using namespace std;
20 | using namespace rapidxml;
21 |
22 | namespace neix
23 | {
24 | class Parser
25 | {
26 | public:
27 | explicit Parser(struct rawRss content);
28 | ~Parser();
29 |
30 | virtual xml_node<>* getFirstNode() = 0;
31 | xml_node<>* getNextNode();
32 | virtual char* getFeedTitle() = 0;
33 | virtual char* getFeedContent() = 0;
34 | virtual char* getFeedLink() = 0;
35 | virtual char* getFeedDate() = 0;
36 | struct rssItem* getFeedItem();
37 |
38 | char* convertHtmlToPlaintext(const char *text);
39 | char* formatTimeString(const char *timeString);
40 | void setTimeFormatUI(const char *format);
41 | char* getTimeFormatUI();
42 | void applyConfig(const vector> config);
43 |
44 | protected:
45 | xml_document<> xmlDocument;
46 | xml_node<> *rootNode{};
47 | xml_node<> *entryNode{};
48 | char* timeFormatUI;
49 |
50 | virtual char* getFeedDateFormat() = 0;
51 | char* getNodeContent(xml_node<> *node);
52 | char* getNodeAttribute(xml_node<> *node, const char *attribute);
53 | void loadXml(struct rawRss rawContent);
54 | };
55 | }
56 |
57 | #endif //NEIX_PARSER_H
58 |
--------------------------------------------------------------------------------
/include/parser/ParserAtom.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Atom parser class.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #ifndef neix_PARSERATOM_H
13 | #define neix_PARSERATOM_H
14 |
15 | #include "rapidxml/rapidxml.hpp"
16 | #include "feed/FeedLoader.h"
17 | #include "Parser.h"
18 |
19 | using namespace rapidxml;
20 |
21 | namespace neix
22 | {
23 | class ParserAtom : public Parser
24 | {
25 | public:
26 | explicit ParserAtom(struct rawRss content);
27 | ~ParserAtom();
28 |
29 | xml_node<>* getFirstNode() override;
30 | char* getFeedTitle() override;
31 | char* getFeedContent() override;
32 | char* getFeedLink() override;
33 | char* getFeedDate() override;
34 |
35 | protected:
36 | char* getFeedDateFormat() override;
37 | };
38 | }
39 |
40 | #endif //neix_PARSERATOM_H
41 |
--------------------------------------------------------------------------------
/include/parser/ParserRSS.h:
--------------------------------------------------------------------------------
1 | /**
2 | * RSS 2.0 parser class.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #ifndef neix_PARSERRSS_H
13 | #define neix_PARSERRSS_H
14 |
15 | #include "rapidxml/rapidxml.hpp"
16 | #include "feed/FeedLoader.h"
17 | #include "Parser.h"
18 |
19 | using namespace rapidxml;
20 |
21 | namespace neix
22 | {
23 | class ParserRSS : public Parser
24 | {
25 | public:
26 | explicit ParserRSS(struct rawRss content);
27 | ~ParserRSS();
28 |
29 | xml_node<>* getFirstNode() override;
30 | char* getFeedTitle() override;
31 | char* getFeedContent() override;
32 | char* getFeedLink() override;
33 | char* getFeedDate() override;
34 |
35 | protected:
36 | char* getFeedDateFormat() override;
37 | };
38 | }
39 |
40 | #endif //neix_PARSERRSS_H
41 |
--------------------------------------------------------------------------------
/include/rapidxml/license.txt:
--------------------------------------------------------------------------------
1 | Use of this software is granted under one of the following two licenses,
2 | to be chosen freely by the user.
3 |
4 | 1. Boost Software License - Version 1.0 - August 17th, 2003
5 | ===============================================================================
6 |
7 | Copyright (c) 2006, 2007 Marcin Kalicinski
8 |
9 | Permission is hereby granted, free of charge, to any person or organization
10 | obtaining a copy of the software and accompanying documentation covered by
11 | this license (the "Software") to use, reproduce, display, distribute,
12 | execute, and transmit the Software, and to prepare derivative works of the
13 | Software, and to permit third-parties to whom the Software is furnished to
14 | do so, all subject to the following:
15 |
16 | The copyright notices in the Software and this entire statement, including
17 | the above license grant, this restriction and the following disclaimer,
18 | must be included in all copies of the Software, in whole or in part, and
19 | all derivative works of the Software, unless such copies or derivative
20 | works are solely in the form of machine-executable object code generated by
21 | a source language processor.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
26 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
27 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
28 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 | DEALINGS IN THE SOFTWARE.
30 |
31 | 2. The MIT License
32 | ===============================================================================
33 |
34 | Copyright (c) 2006, 2007 Marcin Kalicinski
35 |
36 | Permission is hereby granted, free of charge, to any person obtaining a copy
37 | of this software and associated documentation files (the "Software"), to deal
38 | in the Software without restriction, including without limitation the rights
39 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
40 | of the Software, and to permit persons to whom the Software is furnished to do so,
41 | subject to the following conditions:
42 |
43 | The above copyright notice and this permission notice shall be included in all
44 | copies or substantial portions of the Software.
45 |
46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
49 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
52 | IN THE SOFTWARE.
53 |
--------------------------------------------------------------------------------
/include/rapidxml/rapidxml_iterators.hpp:
--------------------------------------------------------------------------------
1 | #ifndef RAPIDXML_ITERATORS_HPP_INCLUDED
2 | #define RAPIDXML_ITERATORS_HPP_INCLUDED
3 |
4 | // Copyright (C) 2006, 2009 Marcin Kalicinski
5 | // Version 1.13
6 | // Revision $DateTime: 2009/05/13 01:46:17 $
7 | //! \file rapidxml_iterators.hpp This file contains rapidxml iterators
8 |
9 | #include "rapidxml.hpp"
10 |
11 | namespace rapidxml
12 | {
13 |
14 | //! Iterator of child nodes of xml_node
15 | template
16 | class node_iterator
17 | {
18 |
19 | public:
20 |
21 | typedef typename xml_node value_type;
22 | typedef typename xml_node &reference;
23 | typedef typename xml_node *pointer;
24 | typedef std::ptrdiff_t difference_type;
25 | typedef std::bidirectional_iterator_tag iterator_category;
26 |
27 | node_iterator()
28 | : m_node(0)
29 | {
30 | }
31 |
32 | node_iterator(xml_node *node)
33 | : m_node(node->first_node())
34 | {
35 | }
36 |
37 | reference operator *() const
38 | {
39 | assert(m_node);
40 | return *m_node;
41 | }
42 |
43 | pointer operator->() const
44 | {
45 | assert(m_node);
46 | return m_node;
47 | }
48 |
49 | node_iterator& operator++()
50 | {
51 | assert(m_node);
52 | m_node = m_node->next_sibling();
53 | return *this;
54 | }
55 |
56 | node_iterator operator++(int)
57 | {
58 | node_iterator tmp = *this;
59 | ++this;
60 | return tmp;
61 | }
62 |
63 | node_iterator& operator--()
64 | {
65 | assert(m_node && m_node->previous_sibling());
66 | m_node = m_node->previous_sibling();
67 | return *this;
68 | }
69 |
70 | node_iterator operator--(int)
71 | {
72 | node_iterator tmp = *this;
73 | ++this;
74 | return tmp;
75 | }
76 |
77 | bool operator ==(const node_iterator &rhs)
78 | {
79 | return m_node == rhs.m_node;
80 | }
81 |
82 | bool operator !=(const node_iterator &rhs)
83 | {
84 | return m_node != rhs.m_node;
85 | }
86 |
87 | private:
88 |
89 | xml_node *m_node;
90 |
91 | };
92 |
93 | //! Iterator of child attributes of xml_node
94 | template
95 | class attribute_iterator
96 | {
97 |
98 | public:
99 |
100 | typedef typename xml_attribute value_type;
101 | typedef typename xml_attribute &reference;
102 | typedef typename xml_attribute *pointer;
103 | typedef std::ptrdiff_t difference_type;
104 | typedef std::bidirectional_iterator_tag iterator_category;
105 |
106 | attribute_iterator()
107 | : m_attribute(0)
108 | {
109 | }
110 |
111 | attribute_iterator(xml_node *node)
112 | : m_attribute(node->first_attribute())
113 | {
114 | }
115 |
116 | reference operator *() const
117 | {
118 | assert(m_attribute);
119 | return *m_attribute;
120 | }
121 |
122 | pointer operator->() const
123 | {
124 | assert(m_attribute);
125 | return m_attribute;
126 | }
127 |
128 | attribute_iterator& operator++()
129 | {
130 | assert(m_attribute);
131 | m_attribute = m_attribute->next_attribute();
132 | return *this;
133 | }
134 |
135 | attribute_iterator operator++(int)
136 | {
137 | attribute_iterator tmp = *this;
138 | ++this;
139 | return tmp;
140 | }
141 |
142 | attribute_iterator& operator--()
143 | {
144 | assert(m_attribute && m_attribute->previous_attribute());
145 | m_attribute = m_attribute->previous_attribute();
146 | return *this;
147 | }
148 |
149 | attribute_iterator operator--(int)
150 | {
151 | attribute_iterator tmp = *this;
152 | ++this;
153 | return tmp;
154 | }
155 |
156 | bool operator ==(const attribute_iterator &rhs)
157 | {
158 | return m_attribute == rhs.m_attribute;
159 | }
160 |
161 | bool operator !=(const attribute_iterator &rhs)
162 | {
163 | return m_attribute != rhs.m_attribute;
164 | }
165 |
166 | private:
167 |
168 | xml_attribute *m_attribute;
169 |
170 | };
171 |
172 | }
173 |
174 | #endif
175 |
--------------------------------------------------------------------------------
/include/rapidxml/rapidxml_print.hpp:
--------------------------------------------------------------------------------
1 | #ifndef RAPIDXML_PRINT_HPP_INCLUDED
2 | #define RAPIDXML_PRINT_HPP_INCLUDED
3 |
4 | // Copyright (C) 2006, 2009 Marcin Kalicinski
5 | // Version 1.13
6 | // Revision $DateTime: 2009/05/13 01:46:17 $
7 | //! \file rapidxml_print.hpp This file contains rapidxml printer implementation
8 |
9 | #include "rapidxml.hpp"
10 |
11 | // Only include streams if not disabled
12 | #ifndef RAPIDXML_NO_STREAMS
13 | #include
14 | #include
15 | #endif
16 |
17 | namespace rapidxml
18 | {
19 |
20 | ///////////////////////////////////////////////////////////////////////
21 | // Printing flags
22 |
23 | const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
24 |
25 | ///////////////////////////////////////////////////////////////////////
26 | // Internal
27 |
28 | //! \cond internal
29 | namespace internal
30 | {
31 |
32 | ///////////////////////////////////////////////////////////////////////////
33 | // Internal character operations
34 |
35 | // Copy characters from given range to given output iterator
36 | template
37 | inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
38 | {
39 | while (begin != end)
40 | *out++ = *begin++;
41 | return out;
42 | }
43 |
44 | // Copy characters from given range to given output iterator and expand
45 | // characters into references (< > ' " &)
46 | template
47 | inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
48 | {
49 | while (begin != end)
50 | {
51 | if (*begin == noexpand)
52 | {
53 | *out++ = *begin; // No expansion, copy character
54 | }
55 | else
56 | {
57 | switch (*begin)
58 | {
59 | case Ch('<'):
60 | *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
61 | break;
62 | case Ch('>'):
63 | *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
64 | break;
65 | case Ch('\''):
66 | *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
67 | break;
68 | case Ch('"'):
69 | *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
70 | break;
71 | case Ch('&'):
72 | *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
73 | break;
74 | default:
75 | *out++ = *begin; // No expansion, copy character
76 | }
77 | }
78 | ++begin; // Step to next character
79 | }
80 | return out;
81 | }
82 |
83 | // Fill given output iterator with repetitions of the same character
84 | template
85 | inline OutIt fill_chars(OutIt out, int n, Ch ch)
86 | {
87 | for (int i = 0; i < n; ++i)
88 | *out++ = ch;
89 | return out;
90 | }
91 |
92 | // Find character
93 | template
94 | inline bool find_char(const Ch *begin, const Ch *end)
95 | {
96 | while (begin != end)
97 | if (*begin++ == ch)
98 | return true;
99 | return false;
100 | }
101 |
102 | ///////////////////////////////////////////////////////////////////////////
103 | // Internal printing operations
104 | template
105 | inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent);
106 |
107 | template
108 | inline OutIt print_attributes(OutIt out, const xml_node *node, int flags);
109 |
110 | template
111 | inline OutIt print_data_node(OutIt out, const xml_node *node, int flags, int indent);
112 |
113 | template
114 | inline OutIt print_cdata_node(OutIt out, const xml_node *node, int flags, int indent);
115 |
116 | template
117 | inline OutIt print_element_node(OutIt out, const xml_node *node, int flags, int indent);
118 |
119 | template
120 | inline OutIt print_declaration_node(OutIt out, const xml_node *node, int flags, int indent);
121 |
122 | template
123 | inline OutIt print_comment_node(OutIt out, const xml_node *node, int flags, int indent);
124 |
125 | template
126 | inline OutIt print_doctype_node(OutIt out, const xml_node *node, int flags, int indent);
127 |
128 | template
129 | inline OutIt print_pi_node(OutIt out, const xml_node *node, int flags, int indent);
130 |
131 |
132 | // Print node
133 | template
134 | inline OutIt print_node(OutIt out, const xml_node *node, int flags, int indent)
135 | {
136 | // Print proper node type
137 | switch (node->type())
138 | {
139 |
140 | // Document
141 | case node_document:
142 | out = print_children(out, node, flags, indent);
143 | break;
144 |
145 | // Element
146 | case node_element:
147 | out = print_element_node(out, node, flags, indent);
148 | break;
149 |
150 | // Data
151 | case node_data:
152 | out = print_data_node(out, node, flags, indent);
153 | break;
154 |
155 | // CDATA
156 | case node_cdata:
157 | out = print_cdata_node(out, node, flags, indent);
158 | break;
159 |
160 | // Declaration
161 | case node_declaration:
162 | out = print_declaration_node(out, node, flags, indent);
163 | break;
164 |
165 | // Comment
166 | case node_comment:
167 | out = print_comment_node(out, node, flags, indent);
168 | break;
169 |
170 | // Doctype
171 | case node_doctype:
172 | out = print_doctype_node(out, node, flags, indent);
173 | break;
174 |
175 | // Pi
176 | case node_pi:
177 | out = print_pi_node(out, node, flags, indent);
178 | break;
179 |
180 | // Unknown
181 | default:
182 | assert(0);
183 | break;
184 | }
185 |
186 | // If indenting not disabled, add line break after node
187 | if (!(flags & print_no_indenting))
188 | *out = Ch('\n'), ++out;
189 |
190 | // Return modified iterator
191 | return out;
192 | }
193 |
194 | // Print children of the node
195 | template
196 | inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent)
197 | {
198 | for (xml_node *child = node->first_node(); child; child = child->next_sibling())
199 | out = print_node(out, child, flags, indent);
200 | return out;
201 | }
202 |
203 | // Print attributes of the node
204 | template
205 | inline OutIt print_attributes(OutIt out, const xml_node *node, int flags)
206 | {
207 | for (xml_attribute *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
208 | {
209 | if (attribute->name() && attribute->value())
210 | {
211 | // Print attribute name
212 | *out = Ch(' '), ++out;
213 | out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
214 | *out = Ch('='), ++out;
215 | // Print attribute value using appropriate quote type
216 | if (find_char(attribute->value(), attribute->value() + attribute->value_size()))
217 | {
218 | *out = Ch('\''), ++out;
219 | out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
220 | *out = Ch('\''), ++out;
221 | }
222 | else
223 | {
224 | *out = Ch('"'), ++out;
225 | out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
226 | *out = Ch('"'), ++out;
227 | }
228 | }
229 | }
230 | return out;
231 | }
232 |
233 | // Print data node
234 | template
235 | inline OutIt print_data_node(OutIt out, const xml_node *node, int flags, int indent)
236 | {
237 | assert(node->type() == node_data);
238 | if (!(flags & print_no_indenting))
239 | out = fill_chars(out, indent, Ch('\t'));
240 | out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
241 | return out;
242 | }
243 |
244 | // Print data node
245 | template
246 | inline OutIt print_cdata_node(OutIt out, const xml_node *node, int flags, int indent)
247 | {
248 | assert(node->type() == node_cdata);
249 | if (!(flags & print_no_indenting))
250 | out = fill_chars(out, indent, Ch('\t'));
251 | *out = Ch('<'); ++out;
252 | *out = Ch('!'); ++out;
253 | *out = Ch('['); ++out;
254 | *out = Ch('C'); ++out;
255 | *out = Ch('D'); ++out;
256 | *out = Ch('A'); ++out;
257 | *out = Ch('T'); ++out;
258 | *out = Ch('A'); ++out;
259 | *out = Ch('['); ++out;
260 | out = copy_chars(node->value(), node->value() + node->value_size(), out);
261 | *out = Ch(']'); ++out;
262 | *out = Ch(']'); ++out;
263 | *out = Ch('>'); ++out;
264 | return out;
265 | }
266 |
267 | // Print element node
268 | template
269 | inline OutIt print_element_node(OutIt out, const xml_node *node, int flags, int indent)
270 | {
271 | assert(node->type() == node_element);
272 |
273 | // Print element name and attributes, if any
274 | if (!(flags & print_no_indenting))
275 | out = fill_chars(out, indent, Ch('\t'));
276 | *out = Ch('<'), ++out;
277 | out = copy_chars(node->name(), node->name() + node->name_size(), out);
278 | out = print_attributes(out, node, flags);
279 |
280 | // If node is childless
281 | if (node->value_size() == 0 && !node->first_node())
282 | {
283 | // Print childless node tag ending
284 | *out = Ch('/'), ++out;
285 | *out = Ch('>'), ++out;
286 | }
287 | else
288 | {
289 | // Print normal node tag ending
290 | *out = Ch('>'), ++out;
291 |
292 | // Test if node contains a single data node only (and no other nodes)
293 | xml_node *child = node->first_node();
294 | if (!child)
295 | {
296 | // If node has no children, only print its value without indenting
297 | out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
298 | }
299 | else if (child->next_sibling() == 0 && child->type() == node_data)
300 | {
301 | // If node has a sole data child, only print its value without indenting
302 | out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
303 | }
304 | else
305 | {
306 | // Print all children with full indenting
307 | if (!(flags & print_no_indenting))
308 | *out = Ch('\n'), ++out;
309 | out = print_children(out, node, flags, indent + 1);
310 | if (!(flags & print_no_indenting))
311 | out = fill_chars(out, indent, Ch('\t'));
312 | }
313 |
314 | // Print node end
315 | *out = Ch('<'), ++out;
316 | *out = Ch('/'), ++out;
317 | out = copy_chars(node->name(), node->name() + node->name_size(), out);
318 | *out = Ch('>'), ++out;
319 | }
320 | return out;
321 | }
322 |
323 | // Print declaration node
324 | template
325 | inline OutIt print_declaration_node(OutIt out, const xml_node *node, int flags, int indent)
326 | {
327 | // Print declaration start
328 | if (!(flags & print_no_indenting))
329 | out = fill_chars(out, indent, Ch('\t'));
330 | *out = Ch('<'), ++out;
331 | *out = Ch('?'), ++out;
332 | *out = Ch('x'), ++out;
333 | *out = Ch('m'), ++out;
334 | *out = Ch('l'), ++out;
335 |
336 | // Print attributes
337 | out = print_attributes(out, node, flags);
338 |
339 | // Print declaration end
340 | *out = Ch('?'), ++out;
341 | *out = Ch('>'), ++out;
342 |
343 | return out;
344 | }
345 |
346 | // Print comment node
347 | template
348 | inline OutIt print_comment_node(OutIt out, const xml_node *node, int flags, int indent)
349 | {
350 | assert(node->type() == node_comment);
351 | if (!(flags & print_no_indenting))
352 | out = fill_chars(out, indent, Ch('\t'));
353 | *out = Ch('<'), ++out;
354 | *out = Ch('!'), ++out;
355 | *out = Ch('-'), ++out;
356 | *out = Ch('-'), ++out;
357 | out = copy_chars(node->value(), node->value() + node->value_size(), out);
358 | *out = Ch('-'), ++out;
359 | *out = Ch('-'), ++out;
360 | *out = Ch('>'), ++out;
361 | return out;
362 | }
363 |
364 | // Print doctype node
365 | template
366 | inline OutIt print_doctype_node(OutIt out, const xml_node *node, int flags, int indent)
367 | {
368 | assert(node->type() == node_doctype);
369 | if (!(flags & print_no_indenting))
370 | out = fill_chars(out, indent, Ch('\t'));
371 | *out = Ch('<'), ++out;
372 | *out = Ch('!'), ++out;
373 | *out = Ch('D'), ++out;
374 | *out = Ch('O'), ++out;
375 | *out = Ch('C'), ++out;
376 | *out = Ch('T'), ++out;
377 | *out = Ch('Y'), ++out;
378 | *out = Ch('P'), ++out;
379 | *out = Ch('E'), ++out;
380 | *out = Ch(' '), ++out;
381 | out = copy_chars(node->value(), node->value() + node->value_size(), out);
382 | *out = Ch('>'), ++out;
383 | return out;
384 | }
385 |
386 | // Print pi node
387 | template
388 | inline OutIt print_pi_node(OutIt out, const xml_node *node, int flags, int indent)
389 | {
390 | assert(node->type() == node_pi);
391 | if (!(flags & print_no_indenting))
392 | out = fill_chars(out, indent, Ch('\t'));
393 | *out = Ch('<'), ++out;
394 | *out = Ch('?'), ++out;
395 | out = copy_chars(node->name(), node->name() + node->name_size(), out);
396 | *out = Ch(' '), ++out;
397 | out = copy_chars(node->value(), node->value() + node->value_size(), out);
398 | *out = Ch('?'), ++out;
399 | *out = Ch('>'), ++out;
400 | return out;
401 | }
402 |
403 | }
404 | //! \endcond
405 |
406 | ///////////////////////////////////////////////////////////////////////////
407 | // Printing
408 |
409 | //! Prints XML to given output iterator.
410 | //! \param out Output iterator to print to.
411 | //! \param node Node to be printed. Pass xml_document to print entire document.
412 | //! \param flags Flags controlling how XML is printed.
413 | //! \return Output iterator pointing to position immediately after last character of printed text.
414 | template
415 | inline OutIt print(OutIt out, const xml_node &node, int flags = 0)
416 | {
417 | return internal::print_node(out, &node, flags, 0);
418 | }
419 |
420 | #ifndef RAPIDXML_NO_STREAMS
421 |
422 | //! Prints XML to given output stream.
423 | //! \param out Output stream to print to.
424 | //! \param node Node to be printed. Pass xml_document to print entire document.
425 | //! \param flags Flags controlling how XML is printed.
426 | //! \return Output stream.
427 | template
428 | inline std::basic_ostream &print(std::basic_ostream &out, const xml_node &node, int flags = 0)
429 | {
430 | print(std::ostream_iterator(out), node, flags);
431 | return out;
432 | }
433 |
434 | //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
435 | //! \param out Output stream to print to.
436 | //! \param node Node to be printed.
437 | //! \return Output stream.
438 | template
439 | inline std::basic_ostream &operator <<(std::basic_ostream &out, const xml_node &node)
440 | {
441 | return print(out, node);
442 | }
443 |
444 | #endif
445 |
446 | }
447 |
448 | #endif
449 |
--------------------------------------------------------------------------------
/include/rapidxml/rapidxml_utils.hpp:
--------------------------------------------------------------------------------
1 | #ifndef RAPIDXML_UTILS_HPP_INCLUDED
2 | #define RAPIDXML_UTILS_HPP_INCLUDED
3 |
4 | // Copyright (C) 2006, 2009 Marcin Kalicinski
5 | // Version 1.13
6 | // Revision $DateTime: 2009/05/13 01:46:17 $
7 | //! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
8 | //! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
9 |
10 | #include "rapidxml.hpp"
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | namespace rapidxml
17 | {
18 |
19 | //! Represents data loaded from a file
20 | template
21 | class file
22 | {
23 |
24 | public:
25 |
26 | //! Loads file into the memory. Data will be automatically destroyed by the destructor.
27 | //! \param filename Filename to load.
28 | file(const char *filename)
29 | {
30 | using namespace std;
31 |
32 | // Open stream
33 | basic_ifstream stream(filename, ios::binary);
34 | if (!stream)
35 | throw runtime_error(string("cannot open file ") + filename);
36 | stream.unsetf(ios::skipws);
37 |
38 | // Determine stream size
39 | stream.seekg(0, ios::end);
40 | size_t size = stream.tellg();
41 | stream.seekg(0);
42 |
43 | // Load data and add terminating 0
44 | m_data.resize(size + 1);
45 | stream.read(&m_data.front(), static_cast(size));
46 | m_data[size] = 0;
47 | }
48 |
49 | //! Loads file into the memory. Data will be automatically destroyed by the destructor
50 | //! \param stream Stream to load from
51 | file(std::basic_istream &stream)
52 | {
53 | using namespace std;
54 |
55 | // Load data and add terminating 0
56 | stream.unsetf(ios::skipws);
57 | m_data.assign(istreambuf_iterator(stream), istreambuf_iterator());
58 | if (stream.fail() || stream.bad())
59 | throw runtime_error("error reading stream");
60 | m_data.push_back(0);
61 | }
62 |
63 | //! Gets file data.
64 | //! \return Pointer to data of file.
65 | Ch *data()
66 | {
67 | return &m_data.front();
68 | }
69 |
70 | //! Gets file data.
71 | //! \return Pointer to data of file.
72 | const Ch *data() const
73 | {
74 | return &m_data.front();
75 | }
76 |
77 | //! Gets file data size.
78 | //! \return Size of file data, in characters.
79 | std::size_t size() const
80 | {
81 | return m_data.size();
82 | }
83 |
84 | private:
85 |
86 | std::vector m_data; // File data
87 |
88 | };
89 |
90 | //! Counts children of node. Time complexity is O(n).
91 | //! \return Number of children of node
92 | template
93 | inline std::size_t count_children(xml_node *node)
94 | {
95 | xml_node *child = node->first_node();
96 | std::size_t count = 0;
97 | while (child)
98 | {
99 | ++count;
100 | child = child->next_sibling();
101 | }
102 | return count;
103 | }
104 |
105 | //! Counts attributes of node. Time complexity is O(n).
106 | //! \return Number of attributes of node
107 | template
108 | inline std::size_t count_attributes(xml_node *node)
109 | {
110 | xml_attribute *attr = node->first_attribute();
111 | std::size_t count = 0;
112 | while (attr)
113 | {
114 | ++count;
115 | attr = attr->next_attribute();
116 | }
117 | return count;
118 | }
119 |
120 | }
121 |
122 | #endif
123 |
--------------------------------------------------------------------------------
/screenshots/.gitkeep:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/screenshots/neix-v0.1.3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qw3rtty/neix/9924d7d52d67a3125882e3905497159a6af0b3c0/screenshots/neix-v0.1.3.gif
--------------------------------------------------------------------------------
/screenshots/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qw3rtty/neix/9924d7d52d67a3125882e3905497159a6af0b3c0/screenshots/screenshot-1.png
--------------------------------------------------------------------------------
/screenshots/screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qw3rtty/neix/9924d7d52d67a3125882e3905497159a6af0b3c0/screenshots/screenshot-2.png
--------------------------------------------------------------------------------
/screenshots/screenshot-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qw3rtty/neix/9924d7d52d67a3125882e3905497159a6af0b3c0/screenshots/screenshot-3.png
--------------------------------------------------------------------------------
/screenshots/screenshot-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qw3rtty/neix/9924d7d52d67a3125882e3905497159a6af0b3c0/screenshots/screenshot-4.png
--------------------------------------------------------------------------------
/src/application/Application.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Terminal UI class.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | #include "config.h"
17 | #include "helper/helper.h"
18 | #include "helper/TextConverter.h"
19 | #include "application/Application.h"
20 | #include "application/ApplicationWindow.h"
21 | #include "feed/Feeds.h"
22 |
23 | #define REFLOW_LIMIT 60
24 |
25 | using namespace std;
26 | using namespace neix;
27 |
28 | /**
29 | * Constructor
30 | */
31 | Application::Application()
32 | {
33 | this->initChoices();
34 |
35 | initscr();
36 | keypad(stdscr, TRUE);
37 | erase();
38 | noecho();
39 | cbreak();
40 | curs_set(0);
41 |
42 | this->openCommand = "";
43 | this->reading = false;
44 | this->createFeedWindow();
45 | this->createArticleWindow();
46 | this->createReadWindow();
47 | }
48 |
49 |
50 | /**
51 | * Destructor
52 | */
53 | Application::~Application()
54 | {
55 | clrtoeol();
56 | refresh();
57 | endwin();
58 | }
59 |
60 |
61 | /**
62 | * Initialize choices
63 | */
64 | void Application::initChoices()
65 | {
66 | this->choice = 0;
67 | this->articleChoice = 0;
68 | this->quit = -1;
69 | }
70 |
71 |
72 | /**
73 | * Create's feed window
74 | */
75 | void Application::createFeedWindow()
76 | {
77 | if (COLS > REFLOW_LIMIT)
78 | {
79 | this->feedWindowWidth = (int) (COLS / 3);
80 | this->feedWindowHeight = LINES-4;
81 | }
82 | else
83 | {
84 | this->feedWindowWidth = COLS;
85 | this->feedWindowHeight = (int) (LINES-4)/4;
86 | }
87 | this->fw.setDimensions(this->feedWindowHeight, this->feedWindowWidth);
88 | this->fw.setPosition(2, 0);
89 | }
90 |
91 |
92 | /**
93 | * Create's article window
94 | */
95 | void Application::createArticleWindow()
96 | {
97 | if (COLS > REFLOW_LIMIT)
98 | {
99 | this->articleWindowWidth = (int) (COLS * 2 / 3);
100 | this->articleWindowHeight = LINES-4;
101 | }
102 | else
103 | {
104 | this->articleWindowWidth = COLS;
105 | this->articleWindowHeight = (int) ((LINES-4) * 3) / 4 ;
106 | }
107 |
108 | this->aw.setDimensions(this->articleWindowHeight, this->articleWindowWidth);
109 |
110 | if (COLS > REFLOW_LIMIT)
111 | this->aw.setPosition(2, this->feedWindowWidth);
112 | else
113 | this->aw.setPosition(this->feedWindowHeight+2, 0);
114 | }
115 |
116 | /**
117 | * Create's read window
118 | */
119 | void Application::createReadWindow()
120 | {
121 | this->rw.setDimensions(this->articleWindowHeight, this->articleWindowWidth);
122 | if (COLS > REFLOW_LIMIT)
123 | {
124 | this->rw.setPosition(2, this->feedWindowWidth);
125 | }
126 | else
127 | {
128 | this->rw.setPosition(this->feedWindowHeight+2, 0);
129 | }
130 |
131 | this->rw.enableHighlight = false;
132 | this->rw.scrollAlways = true;
133 | }
134 |
135 |
136 | /**
137 | * Resize complete application
138 | */
139 | void Application::resize()
140 | {
141 | endwin();
142 | refresh();
143 | erase();
144 |
145 | this->printVersion();
146 | this->printControlHints();
147 |
148 | this->createFeedWindow();
149 | this->createArticleWindow();
150 | this->createReadWindow();
151 | this->fillWindowsWithContent();
152 | this->printWindows();
153 |
154 | if (this->reading)
155 | {
156 | this->openArticle();
157 | }
158 | }
159 |
160 |
161 | /**
162 | * Print current version line
163 | */
164 | void Application::printVersion()
165 | {
166 | attron(A_REVERSE);
167 | mvprintw(1, 0, " neix %s ", VERSION);
168 | attroff(A_REVERSE);
169 | }
170 |
171 |
172 | /**
173 | * Print control hints
174 | */
175 | void Application::printControlHints()
176 | {
177 | attron(A_REVERSE);
178 | if (COLS >= 85)
179 | mvprintw(LINES - 2, 0, " q/<- : Close | ENTER/-> : Open | o : Open Browser | j/J/PGDN : Down | k/K/PGUP : Up ");
180 | else
181 | mvprintw(LINES - 2, 0, "q/←|↵/→|o|j/J/PGDN/↑|k/K/PGUP/↓");
182 |
183 | attroff(A_REVERSE);
184 | }
185 |
186 |
187 | /**
188 | * Show's complete UI
189 | */
190 | void Application::show()
191 | {
192 | Feeds *feeds = Feeds::getInstance();
193 | this->printVersion();
194 | this->printControlHints();
195 |
196 | refresh();
197 | this->fillWindowsWithContent();
198 | this->printWindows();
199 |
200 | while (true)
201 | {
202 | this->c = getch();
203 | int feedCount = feeds->getCount();
204 | int articleCount = feeds->getFeed(this->choice)->articleCount;
205 | switch (this->c)
206 | {
207 | case KEY_R:
208 | case KEY_RESIZE:
209 | this->resize();
210 | break;
211 |
212 | case KEY_UP:
213 | case KEY_K:
214 | if (this->reading)
215 | {
216 | this->rw.scrollUp();
217 | this->rw.update();
218 | }
219 | else
220 | {
221 | this->aw.decreaseHighlight();
222 | this->aw.update();
223 | this->aw.scrollUp();
224 | this->articleChoice = this->decreaseChoice(this->articleChoice, articleCount);
225 | }
226 | break;
227 |
228 | case KEY_DOWN:
229 | case KEY_J:
230 | if (this->reading)
231 | {
232 | this->rw.scrollDown();
233 | this->rw.update();
234 | }
235 | else
236 | {
237 | this->aw.increaseHighlight();
238 | this->aw.update();
239 | this->aw.scrollDown();
240 | this->articleChoice = this->increaseChoice(this->articleChoice, articleCount);
241 | }
242 | break;
243 |
244 | case KEY_PPAGE:
245 | case KEY_UPPER_K:
246 | if (this->reading)
247 | {
248 | break;
249 | }
250 |
251 | this->articleChoice = 0;
252 | this->fw.decreaseHighlight();
253 | this->fw.scrollUp();
254 | this->fw.update();
255 | this->choice = this->decreaseChoice(this->choice, feedCount);
256 |
257 | this->aw.reset();
258 | this->aw.resetHighlight();
259 | this->printArticlesInWindow();
260 | this->aw.update();
261 | break;
262 |
263 | case KEY_NPAGE:
264 | case KEY_UPPER_J:
265 | if (this->reading)
266 | {
267 | break;
268 | }
269 |
270 | this->articleChoice = 0;
271 | this->fw.increaseHighlight();
272 | this->fw.scrollDown();
273 | this->fw.update();
274 | this->choice = this->increaseChoice(this->choice, feedCount);
275 |
276 | this->aw.reset();
277 | this->aw.resetHighlight();
278 | this->printArticlesInWindow();
279 | this->aw.update();
280 | break;
281 |
282 | case KEY_O:
283 | this->openArticleLink();
284 | break;
285 |
286 | case KEY_RIGHT:
287 | case ENTER:
288 | this->aw.hide();
289 | this->openArticle();
290 |
291 | this->fw.reset();
292 | this->printFeedsInWindow();
293 | this->fw.update();
294 | break;
295 |
296 | case KEY_LEFT:
297 | case KEY_Q:
298 | if (this->reading)
299 | {
300 | this->reading = false;
301 | this->rw.reset();
302 | this->rw.hide();
303 |
304 | this->aw.resetContent();
305 | this->printArticlesInWindow();
306 | this->aw.show();
307 | }
308 | else
309 | {
310 | this->quit = this->choice;
311 | }
312 | break;
313 |
314 | default:
315 | mvprintw(LINES - 1, 0, "Character pressed is = %3d Hopefully it can be printed as '%c'", c, c);
316 | refresh();
317 | break;
318 | }
319 |
320 | if (this->quit != -1)
321 | {
322 | break;
323 | }
324 | }
325 | }
326 |
327 |
328 | /**
329 | * Print all main window's to the screen
330 | */
331 | void Application::printWindows()
332 | {
333 | this->fw.show();
334 | if (!this->reading)
335 | {
336 | this->aw.show();
337 | }
338 | }
339 |
340 |
341 | /**
342 | * Print's all pad's to the screen
343 | */
344 | void Application::fillWindowsWithContent()
345 | {
346 | this->printFeedsInWindow();
347 | this->printArticlesInWindow();
348 | }
349 |
350 |
351 | /**
352 | * Print's feeds in window
353 | */
354 | void Application::printFeedsInWindow()
355 | {
356 | this->fw.resetContent();
357 | Feeds *feeds = Feeds::getInstance();
358 | for (int i = 0; i < feeds->getCount(); ++i)
359 | {
360 | char *line = feeds->getFeedLineTitle(i, this->feedWindowWidth-12);
361 | this->fw.pushContent(line);
362 | }
363 | }
364 |
365 |
366 | /**
367 | * Print's articles in window
368 | */
369 | void Application::printArticlesInWindow()
370 | {
371 | if (this->reading)
372 | {
373 | return;
374 | }
375 |
376 | this->aw.resetContent();
377 | Feeds *feeds = Feeds::getInstance();
378 | struct rss* feed = feeds->getFeed(this->choice);
379 |
380 | if (feed->loading && feed->articleCount == 0)
381 | {
382 | this->aw.pushContent(" Feeds loading ... ");
383 | return;
384 | }
385 | else if (feed->loading && feed->articleCount > 0)
386 | {
387 | feed->loading = false;
388 | }
389 |
390 | if (feed->error)
391 | {
392 | this->aw.pushContent(" Could not parse feed! ");
393 | return;
394 | }
395 |
396 | for (int i = 0; i < feed->articleCount; i++)
397 | {
398 | string line = this->printArticleInWindow(
399 | feeds->getArticle(this->choice, i));
400 | this->aw.pushContent(
401 | subStrWithEndingDots(line, this->articleWindowWidth-4));
402 | }
403 | }
404 |
405 |
406 | /**
407 | * Print standard feed article
408 | *
409 | * @param entry - RSS item to print
410 | */
411 | string Application::printArticleInWindow(struct rssItem *entry)
412 | {
413 | string line;
414 | char *readIcon = (char*)"[*]";
415 | if (entry->read)
416 | {
417 | readIcon = (char*)"[ ]";
418 | }
419 | line = readIcon;
420 |
421 | if (this->articleWindowWidth > 40)
422 | {
423 | line += " ";
424 | line += entry->date;
425 | line += " ";
426 | }
427 | else
428 | {
429 | line += " ";
430 | }
431 | string title(entry->title);
432 | line += title;
433 |
434 | return subStrWithEndingDots(line, this->articleWindowWidth-4);
435 | }
436 |
437 |
438 |
439 | /**
440 | * Increase choice
441 | *
442 | * @param new_choice - The new choice index
443 | * @param count - Count of feeds/article
444 | * @return New choice index
445 | */
446 | int Application::increaseChoice(int new_choice, int count)
447 | {
448 | if (new_choice == count-1)
449 | {
450 | new_choice = 0;
451 | }
452 | else
453 | {
454 | ++new_choice;
455 | }
456 |
457 | return new_choice;
458 | }
459 |
460 |
461 | /**
462 | * Decrease choice
463 | *
464 | * @param new_choice - The new choice index
465 | * @param count - Count of feeds/article
466 | * @return New choice index
467 | */
468 | int Application::decreaseChoice(int new_choice, int count)
469 | {
470 | if (new_choice == 0)
471 | {
472 | new_choice = count-1;
473 | }
474 | else
475 | {
476 | --new_choice;
477 | }
478 |
479 | return new_choice;
480 | }
481 |
482 |
483 | /**
484 | * Open selected article in terminal view
485 | */
486 | void Application::openArticle()
487 | {
488 | Feeds *feeds = Feeds::getInstance();
489 | int length = this->articleWindowWidth-4;
490 | this->reading = true;
491 |
492 | struct rss *feed = feeds->getFeed(this->choice);
493 | if (feed->unreadCount > 0)
494 | {
495 | feed->unreadCount--;
496 | }
497 |
498 | struct rssItem *entry = feeds->getArticle(this->choice, this->articleChoice);
499 | entry->read = 1;
500 |
501 | this->rw.reset();
502 |
503 | string line = "Feed: ";
504 | line += feed->title;
505 | this->rw.pushContent(subStrWithEndingDots(line, length));
506 |
507 | line = "Article: ";
508 | line += entry->title;
509 | this->rw.pushContent(subStrWithEndingDots(line, length));
510 |
511 | line = "Date: ";
512 | line += entry->date;
513 | this->rw.pushContent(subStrWithEndingDots(line, length));
514 | this->rw.pushContent("--------");
515 |
516 | if (strlen(entry->description) > 0)
517 | {
518 | TextConverter tc(entry->description, this->renderCommand, length);
519 | this->rw.pushContent(tc.execCmd());
520 | }
521 |
522 | this->rw.show();
523 | }
524 |
525 |
526 | /**
527 | * Open current article link in browser
528 | */
529 | void Application::openArticleLink()
530 | {
531 | if (this->openCommand.empty())
532 | {
533 | return;
534 | }
535 |
536 | Feeds *feeds = Feeds::getInstance();
537 | struct rssItem *article = feeds->getArticle(this->choice, this->articleChoice);
538 | article->read = 1;
539 |
540 | string openCmd = this->openCommand;
541 | openCmd += " ";
542 | openCmd += trim(article->url);
543 |
544 | system(openCmd.c_str());
545 | }
546 |
--------------------------------------------------------------------------------
/src/application/ApplicationWindow.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Application Window class
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #include
13 | #include "application/ApplicationWindow.h"
14 |
15 | using namespace neix;
16 |
17 |
18 | /**
19 | * Constructor
20 | */
21 | ApplicationWindow::ApplicationWindow()
22 | {
23 | this->enableHighlight = true;
24 | this->scrollAlways = false;
25 | this->created = false;
26 | this->y = 0;
27 | this->x = 0;
28 | this->height = 0;
29 | this->width = 0;
30 | this->offsetTop = 0;
31 | this->highlight = 0;
32 | this->win = nullptr;
33 | this->pad = nullptr;
34 | }
35 |
36 |
37 | /**
38 | * Destructor
39 | */
40 | ApplicationWindow::~ApplicationWindow() = default;
41 |
42 |
43 | /**
44 | * Print main window
45 | */
46 | void ApplicationWindow::_printWindow()
47 | {
48 | this->hide();
49 |
50 | box(this->win, 0, 0);
51 | wrefresh(this->win);
52 | }
53 |
54 |
55 | /**
56 | * Print pad
57 | */
58 | void ApplicationWindow::_printPad()
59 | {
60 | prefresh(this->pad, this->offsetTop, 0,
61 | this->y+1, this->x+1, this->height+this->y-2, this->width+this->x);
62 | }
63 |
64 | /**
65 | * Print content of window
66 | */
67 | void ApplicationWindow::_printContent()
68 | {
69 | werase(this->pad);
70 | int x = 0, y = 0, counter = 0;
71 | for (auto & line: this->content)
72 | {
73 | if (this->enableHighlight && this->highlight == counter)
74 | {
75 | wattron(this->pad, A_REVERSE);
76 | mvwprintw(this->pad, y, x, "%s", line.c_str());
77 | wattroff(this->pad, A_REVERSE);
78 | }
79 | else
80 | {
81 | mvwprintw(this->pad, y, x, "%s", line.c_str());
82 | }
83 | y++;
84 | counter++;
85 | }
86 |
87 | this->_printPad();
88 | }
89 |
90 | /**
91 | * Create application window
92 | *
93 | * @return true on success, false else
94 | */
95 | bool ApplicationWindow::_create()
96 | {
97 | this->win = newwin(this->height, this->width, this->y, this->x);
98 | keypad(this->win, TRUE);
99 |
100 | this->pad = newpad(200, this->width-4);
101 | keypad(this->pad, TRUE);
102 |
103 | return this->win != nullptr && this->pad != nullptr;
104 | }
105 |
106 | /**
107 | * Show application window
108 | */
109 | void ApplicationWindow::show()
110 | {
111 | if (!this->created)
112 | {
113 | this->created = this->_create();
114 | }
115 |
116 | this->_printWindow();
117 | this->_printContent();
118 | }
119 |
120 | /**
121 | * Hide application window
122 | */
123 | void ApplicationWindow::hide()
124 | {
125 | refresh();
126 | werase(this->pad);
127 | werase(this->win);
128 | }
129 |
130 |
131 | /**
132 | * Update window
133 | */
134 | void ApplicationWindow::update()
135 | {
136 | this->_printContent();
137 | this->_printPad();
138 | }
139 |
140 |
141 | /**
142 | * Reset window
143 | */
144 | void ApplicationWindow::reset()
145 | {
146 | this->offsetTop = 0;
147 | this->resetContent();
148 | werase(this->pad);
149 | }
150 |
151 | void ApplicationWindow::resetContent()
152 | {
153 | this->content.clear();
154 | }
155 |
156 |
157 | /**
158 | * Reset highlight
159 | */
160 | void ApplicationWindow::resetHighlight()
161 | {
162 | this->highlight = 0;
163 | }
164 |
165 |
166 | /**
167 | * Increase top offset
168 | */
169 | void ApplicationWindow::_increaseOffsetTop()
170 | {
171 | this->offsetTop++;
172 | }
173 |
174 |
175 | /**
176 | * Decrease top offset
177 | */
178 | void ApplicationWindow::_decreaseOffsetTop()
179 | {
180 | this->offsetTop--;
181 | if (this->offsetTop < 0)
182 | {
183 | this->offsetTop = 0;
184 | }
185 | }
186 |
187 |
188 | /**
189 | * Scroll down depending on pushed content elements
190 | */
191 | void ApplicationWindow::_scrollDownDependingOnContentSize()
192 | {
193 | if (this->highlight == 0)
194 | {
195 | this->offsetTop = 0;
196 | }
197 | else if (this->highlight >= this->height-2)
198 | {
199 | this->_increaseOffsetTop();
200 | }
201 | }
202 |
203 |
204 | /**
205 | * Scroll up depending on pushed content elements
206 | */
207 | void ApplicationWindow::_scrollUpDependingOnContentSize()
208 | {
209 | int count = this->content.size();
210 | if (this->highlight == count-1)
211 | {
212 | this->offsetTop = count - (this->height - 2);
213 | }
214 | else if (this->offsetTop > 0)
215 | {
216 | this->_decreaseOffsetTop();
217 | }
218 | }
219 |
220 |
221 | /**
222 | * Scroll window down
223 | */
224 | void ApplicationWindow::scrollDown()
225 | {
226 | if (this->scrollAlways)
227 | {
228 | this->_increaseOffsetTop();
229 | }
230 | else
231 | {
232 | this->_scrollDownDependingOnContentSize();
233 | }
234 |
235 | this->_printPad();
236 | }
237 |
238 |
239 | /**
240 | * Scroll window up
241 | */
242 | void ApplicationWindow::scrollUp()
243 | {
244 | if (this->scrollAlways)
245 | {
246 | this->_decreaseOffsetTop();
247 | }
248 | else
249 | {
250 | this->_scrollUpDependingOnContentSize();
251 | }
252 |
253 |
254 | this->_printPad();
255 | }
256 |
257 |
258 | /**
259 | * Set position of window
260 | *
261 | * @param y
262 | * @param x
263 | */
264 | void ApplicationWindow::setPosition(int y, int x)
265 | {
266 | this->y = y;
267 | this->x = x;
268 |
269 | if (this->created)
270 | {
271 | mvwin(this->win, this->y, this->x);
272 | mvwin(this->pad, this->y+1, this->x+2);
273 | }
274 | }
275 |
276 |
277 | /**
278 | * Set dimensions of window
279 | *
280 | * @param height
281 | * @param width
282 | */
283 | void ApplicationWindow::setDimensions(int height, int width)
284 | {
285 | this->height = height;
286 | this->width = width;
287 |
288 | if (this->created)
289 | {
290 | wresize(this->win, this->height, this->width);
291 | wresize(this->pad, 200, this->width-4);
292 | }
293 | }
294 |
295 |
296 | /**
297 | * Push new content
298 | *
299 | * @param c
300 | */
301 | void ApplicationWindow::pushContent(string c)
302 | {
303 | this->content.push_back(c);
304 | }
305 |
306 |
307 | /**
308 | * Increase choice
309 | */
310 | void ApplicationWindow::increaseHighlight()
311 | {
312 | int count = this->content.size();
313 | if (this->highlight == count-1)
314 | {
315 | this->highlight = 0;
316 | }
317 | else
318 | {
319 | this->highlight++;
320 | }
321 | }
322 |
323 |
324 | /**
325 | * Decrease choice
326 | */
327 | void ApplicationWindow::decreaseHighlight()
328 | {
329 | int count = this->content.size();
330 | if (this->highlight == 0)
331 | {
332 | this->highlight = count-1;
333 | }
334 | else
335 | {
336 | this->highlight--;
337 | }
338 | }
339 |
340 |
341 | /**
342 | * Get ncurses window
343 | */
344 | WINDOW *ApplicationWindow::getWindow()
345 | {
346 | return this->win;
347 | }
348 |
--------------------------------------------------------------------------------
/src/config/ConfigReader.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * Config feed reader.
3 | *
4 | * @package neix
5 | * @author Thomas Schwarz
6 | * @copyright Copyright (c) 2020, Thomas Schwarz
7 | * @license -
8 | * @since Version 0.1.0
9 | * @filesource
10 | */
11 |
12 | #include
13 | #include
14 | #include