3 * Copyright (C) 2008-2009 Didier Villevalois
4 * Copyright (C) 2008-2012 Florian Brosch
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
25 public class Valadoc
.Content
.SourceCode
: ContentElement
, Inline
{
26 public enum Language
{
33 public static Language
from_path (string path
) {
34 int pos
= path
.last_index_of (".");
36 return Language
.UNKNOWN
;
39 string ext
= path
.substring (pos
+ 1);
40 return from_string (ext
, true);
43 public static Language
from_string (string str
, bool is_extension
= false) {
47 return Language
.UNKNOWN
;
49 return Language
.GENIE
;
51 return Language
.GENIE
;
61 return Language
.UNKNOWN
;
64 public unowned
string to_string () {
76 assert_not_reached ();
86 public Run? highlighted_code
{
91 public Language language
{
96 internal SourceCode () {
98 _language
= Language
.VALA
;
101 private string?
get_path (string path
, Api
.Node container
, string source_file_path
,
102 ErrorReporter reporter
)
104 // search relative to our file
105 if (!Path
.is_absolute (path
)) {
106 string relative_to_file
= Path
.build_path (Path
.DIR_SEPARATOR_S
,
107 Path
.get_dirname (source_file_path
),
109 if (FileUtils
.test (relative_to_file
, FileTest
.EXISTS
| FileTest
.IS_REGULAR
)) {
110 return (owned
) relative_to_file
;
114 // search relative to the current directory / absoulte path
115 if (!FileUtils
.test (path
, FileTest
.EXISTS
| FileTest
.IS_REGULAR
)) {
116 string node_segment
= (container is Api
.Package
)?
"" : container
.get_full_name () + ": ";
117 code
= "File '%s' does not exist".printf (path
);
118 reporter
.simple_warning ("%s: %s{{{".printf (source_file_path
, node_segment
),
126 private void load_source_code (string _path
, Api
.Node container
, string source_file_path
,
127 ErrorReporter reporter
)
129 string? path
= get_path (_path
, container
, source_file_path
, reporter
);
135 string content
= null;
136 FileUtils
.get_contents (path
, out content
);
137 _language
= Language
.from_path (path
);
138 code
= (owned
) content
;
139 } catch (FileError err
) {
140 string node_segment
= (container is Api
.Package
)?
"" : container
.get_full_name () + ": ";
141 reporter
.simple_error ("%s: %s{{{".printf (source_file_path
, node_segment
),
142 "Can't read file '%s': %s", path
, err
.message
);
146 private inline
bool is_empty_string (string line
) {
147 for (int i
= 0; line
[i
] != '\0'; i
++) {
148 if (line
[i
].isspace () == false) {
156 private string strip_code (string code
) {
157 string[] lines
= code
.split ("\n");
158 for (int i
= lines
.length
- 1; i
>= 0 && is_empty_string (lines
[i
]); i
--) {
162 string** _lines
= lines
;
163 for (int i
= 0; lines
[i
] != null && is_empty_string (lines
[i
]); i
++) {
164 _lines
= &lines
[i
+ 1];
167 return string.joinv ("\n", (string[]) _lines
);
170 public override void check (Api
.Tree api_root
, Api
.Node container
, string file_path
,
171 ErrorReporter reporter
, Settings settings
)
173 string[] splitted
= code
.split ("\n", 2);
174 if (splitted
[0].strip () == "") {
175 code
= splitted
[1] ??
"";
176 } else if (splitted
[0].has_prefix ("#!")) {
177 unowned
string start
= (string) (((char*) splitted
[0]) + 2);
178 if (start
.has_prefix ("include:")) {
179 start
= (string) (((char*) start
) + 8);
180 string path
= start
.strip ();
181 load_source_code (path
, container
, file_path
, reporter
);
183 string name
= start
._strip ().down ();
184 _language
= Language
.from_string (name
);
185 code
= splitted
[1] ??
"";
186 if (_language
== Language
.UNKNOWN
&& name
!= "none") {
187 string node_segment
= (container is Api
.Package
)?
"" : container
.get_full_name () + ": ";
188 reporter
.simple_warning ("%s: %s{{{".printf (file_path
, node_segment
),
189 "Unsupported programming language '%s'", name
);
194 code
= strip_code (code
);
196 if (_language
== Language
.VALA
) {
197 highlighted_code
= api_root
.highlighter
.highlight_vala (code
);
198 } else if (_language
== Language
.XML
) {
199 highlighted_code
= api_root
.highlighter
.highlight_xml (code
);
200 } else if (_language
== Language
.C
) {
201 highlighted_code
= api_root
.highlighter
.highlight_c (code
);
203 highlighted_code
= new
Run (Run
.Style
.MONOSPACED
);
204 highlighted_code
.content
.add (new
Text (code
));
208 public override void accept (ContentVisitor visitor
) {
209 visitor
.visit_source_code (this
);
212 public override void accept_children (ContentVisitor visitor
) {
213 if (highlighted_code
!= null) {
214 highlighted_code
.accept (visitor
);
218 public override bool is_empty () {
219 // empty source blocks are visible as well
223 public override ContentElement
copy (ContentElement? new_parent
= null) {
224 SourceCode source_code
= new
SourceCode ();
225 source_code
.parent
= new_parent
;
227 source_code
.language
= language
;
228 source_code
.code
= code
;