]> git.lyx.org Git - lyx.git/blob - src/support/os.cpp
Let paragraph::requestSpellcheck() consider contained insets
[lyx.git] / src / support / os.cpp
1 /**
2  * \file os.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Ruurd A. Reitsma
7  * \author Enrico Forestieri
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #ifdef _WIN32
15 # define _WIN32_WINNT 0x0600
16 #endif
17
18 #include "support/convert.h"
19 #include "support/debug.h"
20 #include "support/filetools.h"
21 #include "support/qstring_helpers.h"
22
23 #include <QDir>
24
25 #include <regex>
26
27 #if defined(__CYGWIN__)
28 #include "support/os_cygwin.cpp"
29 #elif defined(_WIN32)
30 #include "support/os_win32.cpp"
31 #else
32 #include "support/os_unix.cpp"
33 #endif
34
35 // Static assert to break compilation on platforms where
36 // int/unsigned int is not 4 bytes. Added to make sure that
37 // e.g., the author hash is always 32-bit.
38 template<bool Condition> struct static_assert_helper;
39 template <> struct static_assert_helper<true> {};
40 enum {
41         dummy = sizeof(static_assert_helper<sizeof(int) == 4>)
42 };
43
44 namespace lyx {
45 namespace support {
46 namespace os {
47
48 int timeout_min()
49 {
50         return 3;
51 }
52
53
54 static string const python23_call(string const & binary, bool verbose = false)
55 {
56         const string version_info = " -c \"from __future__ import print_function;import sys; print(sys.version_info[:2], end=\\\"\\\")\"";
57         // Default to "python" if no binary is given.
58         if (binary.empty())
59                 return "python -tt";
60
61         if (verbose)
62                 lyxerr << "Examining " << binary << "\n";
63         // Check whether this is a python 2 or 3 binary.
64         cmd_ret const out = runCommand(binary + version_info);
65
66         smatch sm;
67         try {
68                 static regex const python_reg("\\((\\d*), (\\d*)\\)");
69                 if (!out.valid || !regex_match(out.result, sm, python_reg))
70                         return string();
71         } catch(regex_error const & /*e*/) {
72                 LYXERR0("Regex error! This should not happen.");
73                 return string();
74         }
75
76         int major = convert<int>(sm.str(1));
77         int minor = convert<int>(sm.str(2));
78         if((major == 2 && minor < 7) || (major == 3 && minor < 5))
79                 return string();
80
81         if (verbose)
82                 lyxerr << "Found Python " << out.result << "\n";
83         // Add the -tt switch so that mixed tab/whitespace
84         // indentation is an error
85         return binary + " -tt";
86 }
87
88
89 static string const find_python_binary()
90 {
91         // This function takes inspiration from PEP 394 and PEP 397
92         // PEP 394 -- The "python" Command on Unix-Like Systems
93         // https://www.python.org/dev/peps/pep-0394/
94         // PEP 397 -- Python launcher for Windows
95         // https://www.python.org/dev/peps/pep-0397/
96
97 #ifdef _WIN32
98         // Check through python launcher whether python 3 is
99         // installed on computer.
100         string command = python23_call("py -3");
101 #else
102         // Check whether python3 in PATH is the right one.
103         string command = python23_call("python3");
104 #endif // _WIN32
105         if (!command.empty())
106                 return command;
107
108 #ifndef _WIN32
109         // python3 does not exists, let us try to find python3.x in PATH
110         // the search is probably broader than required
111         // but we are trying hard to find a valid python binary
112         vector<string> const path = getEnvPath("PATH");
113         lyxerr << "Looking for python 3.x ...\n";
114         for (auto bin : path) {
115                 QString const dir = toqstr(bin);
116                 string const localdir = dir.toLocal8Bit().constData();
117                 QDir qdir(dir);
118                 qdir.setFilter(QDir::Files | QDir::Executable);
119                 QStringList list = qdir.entryList(QStringList("python3*"));
120                 for (auto bin2 : list) {
121                         string const binary = "\"" + addName(localdir,
122                                 bin2.toLocal8Bit().constData()) + "\"";
123                         command = python23_call(binary, true);
124                         if (!command.empty())
125                                 return command;
126                 }
127         }
128 #endif // !_WIN32
129
130         // python 3 was not found let us look for python 2
131 #ifdef _WIN32
132         command = python23_call("py -2");
133 #else
134         command = python23_call("python2");
135 #endif // _WIN32
136         if (!command.empty())
137                 return command;
138
139 #ifdef _WIN32
140         // python launcher is not installed, let cmd auto check 
141         // PATH for a python.exe
142         command = python23_call("python");
143         if (!command.empty())
144                 return command;
145
146         //failed, prepare to search PATH manually
147         vector<string> const path = getEnvPath("PATH");
148         lyxerr << "Manually looking for python in PATH ...\n";
149         QString const exeName = "python*";
150 #else
151         // python2 does not exists, let us try to find python2.x in PATH
152         // the search is probably broader than required
153         // but we are trying hard to find a valid python binary
154         lyxerr << "Looking for python 2.x ...\n";
155         QString const exeName = "python2*";
156 #endif // _WIN32
157
158         for (auto bin : path) {
159                 QString const dir = toqstr(bin);
160                 string const localdir = dir.toLocal8Bit().constData();
161                 QDir qdir(dir);
162                 qdir.setFilter(QDir::Files | QDir::Executable);
163                 QStringList list = qdir.entryList(QStringList(exeName));
164                 for (auto bin2 : list) {
165                         string const binary = "\"" + addName(localdir,
166                                 bin2.toLocal8Bit().constData()) + "\"";
167                         command = python23_call(binary, true);
168                         if (!command.empty())
169                                 return command;
170                 }
171         }
172
173         // If this happens all hope is lost that this is a sane system
174         lyxerr << "Warning: No python v2.x or 3.x binary found.\n";
175         return python23_call("");
176 }
177
178
179 string const python(bool reset)
180 {
181         static string command = find_python_binary();
182         // FIXME THREAD
183         if (reset) {
184                 command = find_python_binary();
185         }
186         return command;
187 }
188
189 } // namespace os
190 } // namespace support
191 } // namespace lyx