├── Commands ├── Autocomplete.tmCommand ├── Convert to format.tmCommand ├── Documentation for Resource.tmCommand ├── Execute SPARQL Query.tmCommand ├── Export visualization.tmCommand ├── Help.tmCommand ├── Register file extensions.tmCommand ├── Remove unused @prefix directives.tmCommand ├── Un-comment selection.tmCommand ├── Validate syntax.tmCommand └── Visualize knowledge base.tmCommand ├── LICENSE ├── Preferences ├── Completion SPARQL1_1.tmPreferences ├── Completion: literal language tags.tmPreferences ├── Completions literal types.tmPreferences ├── Completions: XSD.tmPreferences ├── Symbol list: Hidden.tmPreferences ├── Symbol list: Shown.tmPreferences └── Turtle settings.tmPreferences ├── README.md ├── Snippets ├── #INCLUDE .tmSnippet ├── #QUERY .tmSnippet ├── #UPDATE .tmSnippet ├── BASE.tmSnippet ├── Base directive.tmSnippet ├── Basic.tmSnippet ├── DELETE.tmSnippet ├── Document Skeleton.tmSnippet ├── GRAPH.tmSnippet ├── PREFIX.tmSnippet ├── Prefix Directive.tmSnippet └── SELECT.tmSnippet ├── Support ├── cache │ └── .gitignore ├── css │ ├── .gitignore │ ├── sparql-exec-preview.css │ └── sparql-exec-preview.scss ├── img │ ├── item-icons │ │ ├── Languages.png │ │ ├── Macros.png │ │ ├── Snippets.png │ │ ├── Template Files.png │ │ ├── empty_gray.png │ │ ├── iconmaker.psd │ │ ├── p_red.png │ │ ├── question_gray.png │ │ ├── upper_c_green.png │ │ ├── upper_d_red.png │ │ ├── upper_i_blue.png │ │ ├── upper_p_gray.png │ │ ├── upper_p_purple.png │ │ └── upper_t_blue.png │ ├── screenshot-converter.png │ ├── screenshot-editor.png │ ├── screenshot-menu.png │ ├── screenshot-sparql-exec.png │ ├── screenshot-sparql.png │ ├── screenshot-syntaxval-error.png │ ├── screenshot-syntaxval-success.png │ └── screenshot-visu.png ├── lib │ ├── extractor.xsl │ ├── sparql.rb │ └── turtle.rb └── textmate-runner │ ├── proxy-installer.sh │ └── runner │ └── TextMate2 (TTL:SPARQL).app │ └── Contents │ ├── Info.plist │ ├── MacOS │ └── TextMate Proxy │ └── Resources │ ├── AppSettings.plist │ ├── Application.icns │ ├── MainMenu.nib │ ├── designable.nib │ └── keyedobjects.nib │ ├── SPARQL.icns │ ├── Turtle.icns │ └── script ├── Syntaxes ├── SPARQL.tmLanguage └── Turtle.tmLanguage ├── Templates └── Empty TTL file │ ├── info.plist │ └── template.ttl ├── Tests └── .gitignore ├── Themes └── SemWeb Classic.tmTheme └── info.plist /Commands/Autocomplete.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | # Prevent that input data causes trouble in shell commands 11 | STDIN.read(nil) 12 | 13 | require ENV['TM_BUNDLE_SUPPORT']+'/lib/turtle' 14 | require ENV['TM_SUPPORT_PATH'] + '/lib/exit_codes' 15 | 16 | scope = ENV['TM_SCOPE'] 17 | left_scope = (ENV['TM_SCOPE_LEFT'].nil?) ? '' : ENV['TM_SCOPE_LEFT'] 18 | done = false 19 | 20 | # Control display of list items 21 | icons = { 22 | 'class' => 'Rsc_Class', 23 | 'property' => 'Rsc_Prop', 24 | 'datatype' => 'Rsc_Datatype', 25 | 'instance' => 'Rsc_Instance', 26 | 'datatypeproperty' => 'Rsc_Prop', 27 | 'objectproperty' => 'Rsc_Prop', 28 | 'annotationproperty' => 'Rsc_Prop', 29 | 'transitiveproperty' => 'Rsc_Prop', 30 | 'symmetricproperty' => 'Rsc_Prop', 31 | 'functionalproperty' => 'Rsc_Prop', 32 | 'inversefunctionalproperty' => 'Rsc_Prop', 33 | 'equivalentproperty' => 'Rsc_Prop', 34 | } 35 | icons.default = 'Rsc_Unknown' 36 | sort_dict = { 37 | 'class' => 'class', 38 | 'datatype' => 'datatype', 39 | 'instance' => 'instance', 40 | 'property' => 'property', 41 | 'datatypeproperty' => 'property', 42 | 'objectproperty' => 'property', 43 | 'annotationproperty' => 'property', 44 | 'transitiveproperty' => 'property', 45 | 'symmetricproperty' => 'property', 46 | 'functionalproperty' => 'property', 47 | 'inversefunctionalproperty' => 'property', 48 | 'equivalentproperty' => 'property' 49 | } 50 | sort_dict.default = 'unknown' 51 | 52 | # Autocompletion @prefix directives 53 | if not left_scope.index('meta.spec.prefixID.turtle').nil? or 54 | not left_scope.index('meta.spec.sparqlPrefix.turtle').nil? 55 | given_pref = Word::current_word '(\S*)' 56 | choices = [] 57 | prefixes = Turtle::Prefixes.get_all() 58 | maxlen = prefixes.keys.max.length 59 | prefixes.sort.each do |pair| 60 | pref = pair[0] 61 | uri = pair[1] 62 | choices.push({ 63 | "display" => '%s %s' % [(pref+':').ljust(maxlen + 8), uri], 64 | "insert" => ': <%s>.' % [uri], 65 | "match" => pref, 66 | "image" => 'Prefix' 67 | }) 68 | end 69 | 70 | TextMate::UI.complete(choices, :case_insensitive => true, :extra_chars=>'_<>:.@') 71 | TextMate::exit_show_tool_tip 72 | done = true 73 | end 74 | 75 | # Autocompletion for prefixed resource QNames 76 | if left_scope.index('variable.other.PNAME_NS.turtle') or left_scope.index('support.variable.PN_LOCAL.turtle') 77 | word = Word::current_word '(\S*):(\S*)(?!(?:\.|;)\b)' 78 | # Chop off trailing dot (you got it ... language grammar isn't that solid) 79 | word = word[0..-2] if (word =~ /[.;]$/) 80 | word_frags = word.split(':') 81 | # Try to determine the IRI associated with prefix in current document 82 | iri = Turtle.resolve_URI word_frags[0], ENV['TM_FILEPATH'] 83 | # Build model and query it 84 | model = Turtle::Model.new(word_frags[0], iri) 85 | if (model.available?) 86 | choices = [] 87 | # TODO: Add caching layer for data used by UI.complete 88 | model.resources.sort! do |a,b| 89 | # First order by the resource type, then alphabetically by their name 90 | [ sort_dict[a.attributes['type']], 91 | a.attributes['id'] 92 | ] <=> [ 93 | sort_dict[b.attributes['type']], 94 | b.attributes['id'] 95 | ] 96 | end.each do |rsc| 97 | choices.push({ 98 | 'display' => rsc.attributes['id'].to_s + ' ', 99 | 'match' => rsc.attributes['id'].to_s, 100 | 'insert' => '', 101 | 'image' => icons[rsc.attributes['type'].to_s] 102 | }) 103 | end 104 | 105 | TextMate::UI.complete(choices, :case_insensitive => false, :initial_filter => word_frags[1], :extra_chars=>'_-.:\\') 106 | TextMate::exit_discard 107 | end 108 | done = true 109 | end 110 | 111 | # Default behaviour -- don't replace anything but show it as tooltip instead 112 | if Turtle::DEBUG and not done 113 | puts 'TM_SCOPE: '+ENV['TM_SCOPE'] 114 | if not ENV['TM_SCOPE_LEFT'].nil? 115 | puts 'TM_SCOPE_LEFT: '+ENV['TM_SCOPE_LEFT'] 116 | end 117 | TextMate::exit_show_tool_tip 118 | end 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | input 127 | word 128 | inputFormat 129 | text 130 | keyEquivalent 131 | ~ 132 | name 133 | Autocomplete 134 | outputCaret 135 | afterOutput 136 | outputFormat 137 | text 138 | outputLocation 139 | atCaret 140 | scope 141 | source.turtle, source.sparql 142 | uuid 143 | 5B3DDC52-4AF7-45E5-AC26-837BF81208FE 144 | version 145 | 2 146 | 147 | 148 | -------------------------------------------------------------------------------- /Commands/Convert to format.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | require 'uri' 11 | 12 | require ENV['TM_SUPPORT_PATH'] + '/lib/textmate' 13 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui' 14 | 15 | TextMate::require_cmd 'rapper' 16 | 17 | input_doc = STDIN.read 18 | 19 | # Determine supported output formats 20 | formats = [] 21 | state = :looking 22 | `rapper --help`.each_line do |line| 23 | case state 24 | when :looking 25 | if /-o FORMAT, --output FORMAT/i =~ line 26 | state = :found 27 | end 28 | when :found 29 | if /--/ =~ line 30 | state = :done 31 | elsif /^\s*([^\s]+)\s*\w/ =~ line 32 | formats << Regexp.last_match[1] 33 | else 34 | state = :done 35 | end 36 | when :done 37 | break 38 | end 39 | end 40 | 41 | if ENV['TM_FILEPATH'].nil? 42 | # Unsaved document -> generate unique URN 43 | default_base_uri = "textmate:doc:#{Time.new.to_i}#" 44 | else 45 | # Document exists 46 | # Use file URL of current document as fallback 47 | default_base_uri = URI.escape('file://'+ENV['TM_FILEPATH']+'#') 48 | # when no @base directive exists that we could use 49 | input_doc.each_line do |line| 50 | if /^@base <([^>]+)>\./ =~ line 51 | default_base_uri = Regexp.last_match[1] 52 | break 53 | end 54 | end 55 | end 56 | 57 | # Ask user for some infos 58 | TextMate::exit_discard if ( 59 | base_uri = TextMate::UI.request_string( 60 | :title => 'Base URI', 61 | :prompt => 'Enter custom base URI or accept default', 62 | :default => default_base_uri) 63 | ).nil? or ( 64 | target_fmt = TextMate::UI.request_item( 65 | :title => 'Convert to format', 66 | :prompt => 'Please select target format', 67 | :items => formats) 68 | ).nil? 69 | 70 | # Conversion 71 | cmd = 'rapper -q -i turtle -o \'%s\' - \'%s\' 2>&1' % [target_fmt, base_uri] 72 | IO.popen(cmd, 'w+') do |io| 73 | io << input_doc; io.close_write 74 | puts io.read 75 | end 76 | 77 | input 78 | document 79 | inputFormat 80 | text 81 | keyEquivalent 82 | ^C 83 | name 84 | Convert to format 85 | outputCaret 86 | afterOutput 87 | outputFormat 88 | text 89 | outputLocation 90 | newWindow 91 | scope 92 | source.turtle 93 | uuid 94 | 84B88EA7-7B67-4DC6-9014-76B52BF60CA7 95 | version 96 | 2 97 | 98 | 99 | -------------------------------------------------------------------------------- /Commands/Documentation for Resource.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | require ENV['TM_BUNDLE_SUPPORT']+'/lib/turtle' 11 | require ENV['TM_SUPPORT_PATH'] + '/lib/exit_codes' 12 | 13 | scope = ENV['TM_SCOPE'] || '' 14 | left_scope = ENV['TM_SCOPE_LEFT'] || '' 15 | 16 | if left_scope.index('variable.other.PNAME_NS.turtle') or left_scope.index('support.variable.PN_LOCAL.turtle') 17 | word = Word::current_word('(\S*):(\S*)') 18 | # Chop of trailing dot (language grammar isn't that stable) 19 | word = word[0..-2] if word.end_with? '.' 20 | frags = word.split(':') 21 | # Try to determine the IRI associated with prefix in current document 22 | iri = Turtle.resolve_URI frags[0], ENV['TM_FILEPATH'] 23 | if 2 == frags.length 24 | model = Turtle::Model.new(frags[0], iri) 25 | if model.available? 26 | docu = model.explain(frags[1]) 27 | TextMate::UI.simple_notification( 28 | :title => "Documentation", 29 | :summary => (model.prefix+':'+frags[1]) + ((docu['label']) ? ' — "'+docu['label']+'"' : ''), 30 | :log => docu['description'] || 'Sorry, no documentation available.' 31 | ) 32 | end 33 | end 34 | end 35 | input 36 | line 37 | inputFormat 38 | text 39 | keyEquivalent 40 | ^h 41 | name 42 | Documentation for Resource 43 | outputCaret 44 | afterOutput 45 | outputFormat 46 | text 47 | outputLocation 48 | discard 49 | scope 50 | source.turtle meta.spec.PNAME_LN.turtle, source.sparql meta.spec.PNAME_LN.turtle 51 | uuid 52 | 533BE8C9-42EF-48EF-A1FC-5E831DC46059 53 | version 54 | 2 55 | 56 | 57 | -------------------------------------------------------------------------------- /Commands/Execute SPARQL Query.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | require 'net/http' 11 | require 'uri' 12 | 13 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui' 14 | require ENV['TM_SUPPORT_PATH'] + '/lib/exit_codes' 15 | require ENV['TM_SUPPORT_PATH'] + '/lib/escape' 16 | require ENV['TM_SUPPORT_PATH'] + '/lib/progress' 17 | require ENV['TM_SUPPORT_PATH'] + '/lib/web_preview' 18 | 19 | require ENV['TM_BUNDLE_SUPPORT']+'/lib/sparql' 20 | 21 | 22 | # TODO: An unsupported edge case is left: when a section contains multiple 23 | # update/query markers, only the first ones are taken into account. Add support 24 | # for multiple markers that are chosen in :bottom_up beginning from the line where 25 | # an eventual include marker occurs. 26 | 27 | # Determine line number where query text starts at 28 | if ENV['TM_LINE_NUMBER'].nil? 29 | # No line number provided, use Plan B 30 | # 8:6-16:7 31 | if ENV['TM_SELECTION'] =~ /^(\d+)/ 32 | curr_line = Regexp.last_match[1].to_i 33 | else 34 | # Can't recover 35 | unless ENV['TM_SELECTED_TEXT'].nil? 36 | Turtle::SPARQL.raise_error(:warning, 37 | 'Something weird happened', 38 | 'Can\'t determine the line number of where your selection starts') 39 | end 40 | end 41 | else 42 | curr_line = ENV['TM_LINE_NUMBER'].to_i 43 | end 44 | 45 | # Internally we start counting at zero 46 | curr_line -= 1 47 | 48 | $n_query_sections = 0 49 | def open_query_section(title = nil) 50 | $n_query_sections += 1 51 | alt = ($n_query_sections % 2 == 0) ? 'even' : 'odd' 52 | html = <<-HTML 53 | <div class="query-section #{alt}"> 54 | HTML 55 | return html 56 | end 57 | 58 | def close_query_section() 59 | '</div>' 60 | end 61 | 62 | def write_section_header(succeeded, code, msg = '') 63 | result = succeeded ? 'success' : 'error' 64 | html = <<-HTML 65 | <div class="header #{result}"> 66 | <p class="code">#{code}</p> 67 | <p class="message">#{msg}</p> 68 | <div class="clear"></div> 69 | </div> 70 | HTML 71 | return html 72 | end 73 | 74 | def write_query_log(qry) 75 | qry = htmlize(qry) 76 | html = <<-HTML 77 | <div class="query-log"> 78 | <div class="toggler"> 79 | <a href="#" title="Hold shift pressed for toggling all query logs" onclick="var collapse=function(logEl){var s=logEl.style;s.display=(s.display=='none')?'block':'none';};if(arguments[0].shiftKey){var logEls=document.querySelectorAll('.query-log .result');for(var i=0,j=logEls.length; i < j; collapse(logEls.item(i++)));}else{collapse(this.parentNode.nextElementSibling)};return false;">Show/hide the executed query</a> 80 | </div> 81 | <div class="result" style="display:none;"><pre>#{qry}</pre></div> 82 | </div> 83 | HTML 84 | return html 85 | end 86 | 87 | def write_query_result(result) 88 | '<div class="result">'+result+'</div>' 89 | end 90 | 91 | def execute_query(endpoint_type, endpoint_url, qry) 92 | begin 93 | Net::HTTP.start(endpoint_url.host, endpoint_url.port || 80) do |http| 94 | # Remove request timeout limitation (e.g. needed some some DBpedia queries) 95 | http.read_timeout = nil 96 | if endpoint_type == :query 97 | url = endpoint_url.to_s + '?query='+CGI::escape(qry) 98 | req = Net::HTTP::Get.new(url, { 'Accept' => 'text/html, text/plain' }) 99 | else 100 | req = Net::HTTP::Post.new(endpoint_url.path, { 'Accept' => 'text/plain' }) 101 | req.set_form_data({ 'update' => qry }) 102 | end 103 | resp = http.request(req) 104 | log_query(endpoint_type, endpoint_url, qry, req, resp) 105 | end 106 | rescue Errno::EHOSTUNREACH 107 | msg = (endpoint_url.host == 'dbpedia.org') ? 108 | 'Relax. DBpedia seems to be down.' : 109 | "Looks like there is no server connected to the hostname '#{endpoint_url.host}'" 110 | Turtle::SPARQL.raise_error :critical, 'Host not found', msg, false 111 | raise Exception.new 'quiet' 112 | end 113 | end 114 | 115 | def log_query(endpoint_type, endpoint_url, qry, req, resp) 116 | puts open_query_section 117 | puts write_section_header((resp.is_a? Net::HTTPSuccess), resp.code, 'Result of SPARQL '+endpoint_type.to_s.upcase+' query to <u>'+endpoint_url.to_s+'</u>') 118 | puts write_query_log(qry) 119 | if (not resp['Content-Type'].nil?) and resp['Content-Type'].index('text/html') 120 | puts write_query_result(resp.body) 121 | else 122 | puts write_query_result('<pre style="line-height:0.8em;">'+htmlize(resp.body)+'</pre>') 123 | end 124 | puts close_query_section 125 | end 126 | 127 | # Create document at get section that should be executed 128 | doc = Turtle::SPARQL::Document.new(STDIN.read) 129 | section = doc.section_at_line(curr_line) 130 | 131 | Turtle::SPARQL.raise_error(:info, 132 | 'Nothing to do', 'There is no section that spans over the given line number') if section.nil? 133 | 134 | # Prepare preview window 135 | n_queries = section.each_query.count 136 | title_info = (n_queries <= 1) ? '' : "(#{n_queries} queries)" 137 | html_header("SPARQL Results #{title_info}") 138 | puts '<link rel="stylesheet" type="text/css" href="file://'+ENV['TM_BUNDLE_SUPPORT']+'/css/sparql-exec-preview.css"/>' 139 | 140 | cancel_proc = Proc.new do 141 | raise Exception.new 'Execution was cancelled by the user' 142 | Kernel.exit 143 | end 144 | 145 | # Query the SPARQL service and show result to the user 146 | begin 147 | TextMate.call_with_progress( 148 | :title => 'Executing query', 149 | :message => 'Please wait while the SPARQL query is being executed...', 150 | :indeterminate => true, 151 | :cancel => cancel_proc) do 152 | known_eps = {} 153 | section.each_query do |qry| 154 | ep_type = Turtle::SPARQL.which_type? qry 155 | # Make sure we have an appropriate endpoint 156 | unless known_eps.include? ep_type 157 | new_ep = Turtle::SPARQL.get_endpoint ep_type, section 158 | Turtle::SPARQL.raise_error(:warning, 159 | 'No endpoint found', 160 | 'No suitable endpoint marker found') if new_ep.nil? 161 | ep_url = URI(new_ep) 162 | Turtle::SPARQL.raise_error(:critical, 163 | 'Invalid endpoint URL', 164 | 'Only HTTP/S URLs are allowed') unless ep_url.is_a? URI::HTTP 165 | known_eps[ep_type] = ep_url 166 | end 167 | # Execute 168 | execute_query(ep_type, known_eps[ep_type], qry) 169 | end 170 | end 171 | rescue Exception => exc 172 | if not ['quiet', 'Execution was cancelled by the user'].include?(exc.message) 173 | TextMate::UI::alert(:critical, 'Something went wrong', exc.inspect) 174 | end 175 | TextMate::exit_discard 176 | end 177 | 178 | html_footer() 179 | 180 | 181 | 182 | 183 | 184 | 185 | input 186 | document 187 | inputFormat 188 | text 189 | keyEquivalent 190 | @r 191 | name 192 | Execute SPARQL Query 193 | outputCaret 194 | afterOutput 195 | outputFormat 196 | html 197 | outputLocation 198 | newWindow 199 | scope 200 | source.sparql 201 | semanticClass 202 | process.external.run.sparql.turtle 203 | uuid 204 | EF6E5E32-54FD-4AE1-B35E-CC16DFE18D13 205 | version 206 | 2 207 | 208 | 209 | -------------------------------------------------------------------------------- /Commands/Export visualization.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | saveActiveFile 7 | command 8 | #!/usr/bin/env bash 9 | [[ -f "${TM_SUPPORT_PATH}/lib/bash_init.sh" ]] && . "${TM_SUPPORT_PATH}/lib/bash_init.sh" 10 | 11 | set -o pipefail 12 | 13 | dlg_result=$("$DIALOG" filepanel --isSavePanel --title "Save visualization" \ 14 | --label "Select where Graphviz should save the generated PDF file:" \ 15 | --defaultDirectory "$TM_DIRECTORY" --filename "$TM_FILENAME.pdf") 16 | 17 | if [[ "$dlg_result" =~ \<string\>([^\<]+)\</string\> ]]; then 18 | target_file=${BASH_REMATCH[1]} 19 | else 20 | echo "ABORTED (No output file selected)" 21 | exit 22 | fi 23 | 24 | # Partytime 25 | "${TM_RAPPER:-rapper}" -i turtle -o dot "$TM_FILEPATH" \ 26 | -f 'resourceFill="#ff0000"' \ 27 | -f 'literalFill="#00ff00"' \ 28 | -f 'bnodeFill="#0000ff"' \ 29 | -f 'resourceBorder="#ffffff"' \ 30 | -f 'bnodeBorder="#ffffff"' \ 31 | -f 'literalBorder="#ffffff"' \ 32 | | sed 's|(Unknown)|'$TM_FILEPATH'|g' \ 33 | | "${TM_DOT:-dot}" -Tpdf -o "$target_file" 34 | 35 | # Some final status info so that user can see at first glance if everything went fine or not 36 | status=$? 37 | echo "-------" 38 | if [[ $status == 0 ]] ; then 39 | echo "SUCCESS" 40 | else 41 | echo "ERROR" 42 | fi 43 | 44 | 45 | input 46 | none 47 | inputFormat 48 | text 49 | keyEquivalent 50 | ~@S 51 | name 52 | Export Visualization 53 | outputCaret 54 | afterOutput 55 | outputFormat 56 | text 57 | outputLocation 58 | toolTip 59 | requiredCommands 60 | 61 | 62 | command 63 | dot 64 | locations 65 | 66 | /usr/local/bin/dot 67 | /opt/local/bin/dot 68 | /usr/bin/dot 69 | 70 | variable 71 | TM_DOT 72 | 73 | 74 | command 75 | rapper 76 | locations 77 | 78 | /usr/local/bin/rapper 79 | /opt/local/bin/rapper 80 | /usr/bin/rapper 81 | 82 | variable 83 | TM_RAPPER 84 | 85 | 86 | scope 87 | source.turtle 88 | semanticClass 89 | process.external.save.turtle 90 | uuid 91 | C2509D61-BA70-4202-AD5A-9307266295C5 92 | version 93 | 2 94 | 95 | 96 | -------------------------------------------------------------------------------- /Commands/Help.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env bash 9 | [[ -f "${TM_SUPPORT_PATH}/lib/bash_init.sh" ]] && . "${TM_SUPPORT_PATH}/lib/bash_init.sh" 10 | 11 | . "$TM_SUPPORT_PATH/lib/webpreview.sh" 12 | html_header "About the Turtle bundle" "Turtle" 13 | 14 | # Rewrite relative paths 15 | 16 | cd "$TM_BUNDLE_SUPPORT/.." 17 | supp_dir="`pwd | sed 's/ /%20/'`/Support" 18 | sed "s#(\./Support#(file://$supp_dir#" README.md | "$TM_SUPPORT_PATH/lib/markdown_to_help.rb" 19 | 20 | html_footer 21 | 22 | 23 | input 24 | none 25 | inputFormat 26 | text 27 | keyEquivalent 28 | @y 29 | name 30 | Help 31 | outputCaret 32 | afterOutput 33 | outputFormat 34 | html 35 | outputLocation 36 | newWindow 37 | scope 38 | source.turtle 39 | semanticClass 40 | action.turtle.help 41 | uuid 42 | 72E360B7-71C7-4E4C-B78A-A106FB618FF2 43 | version 44 | 2 45 | 46 | 47 | -------------------------------------------------------------------------------- /Commands/Register file extensions.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui' 11 | 12 | Dir.chdir ENV['TM_BUNDLE_SUPPORT'] + '/textmate-runner' 13 | 14 | do_register = TextMate::UI.request_confirmation( 15 | :button1 => "Yes", 16 | :button2 => "No", 17 | :title => "Un-/Register file extensions", 18 | :prompt => 'Open all .ttl/.sparql files with TextMate?') 19 | 20 | op = (do_register) ? 'install' : 'unistall' 21 | `./proxy-installer.sh ${op}` 22 | 23 | TextMate::UI.alert(:informational, 'Un-/Register file extensions', (do_register) ? 'File extensions registered' : 'File extensions unregistered') 24 | input 25 | none 26 | inputFormat 27 | text 28 | name 29 | Register file extensions 30 | outputCaret 31 | afterOutput 32 | outputFormat 33 | text 34 | outputLocation 35 | toolTip 36 | uuid 37 | 2F74EEC6-5174-443B-B314-781BCA3A0E85 38 | version 39 | 2 40 | 41 | 42 | -------------------------------------------------------------------------------- /Commands/Remove unused @prefix directives.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui' 11 | require ENV['TM_SUPPORT_PATH'] + '/lib/escape' 12 | 13 | PATTERN = /^@prefix ([^\s:]+): <[^>]+>\.$/ 14 | 15 | doc = STDIN.read 16 | removed = [] 17 | 18 | # Strip out unused @prefix directives 19 | doc.each_line do |line| 20 | if line =~ PATTERN 21 | prefix = Regexp.last_match.captures[0] 22 | unless doc =~ /#{prefix}:[^ ]/ 23 | removed.push htmlize(line) 24 | next 25 | end 26 | end 27 | puts line 28 | end 29 | 30 | if removed.any? 31 | # Tell user what happened 32 | TextMate::UI.tool_tip <<-HTML, :format=>:html, :transparent=>true 33 | <div style="font-size:1.1em; font-family:\'Lucida Grande\';padding:3px 4px;background-color:#ffffaa;color:#333333;"> 34 | <h2 style="color:#000000;margin:0 0 5px 0;font-size:1.2em;">#{removed.length} directive(s) removed</h2> 35 | <ul style="margin:0;padding:0 4px 0 20px;list-style-type:square;"> 36 | <li>#{removed.join '</li><li>'}</li> 37 | </ul> 38 | </div> 39 | HTML 40 | end 41 | 42 | input 43 | document 44 | inputFormat 45 | text 46 | keyEquivalent 47 | ~@p 48 | name 49 | Remove unused @prefix directives 50 | outputCaret 51 | afterOutput 52 | outputFormat 53 | text 54 | outputLocation 55 | replaceDocument 56 | scope 57 | source.turtle 58 | uuid 59 | EB08FE12-95D5-42DA-80DE-2B8E1D18B009 60 | version 61 | 2 62 | 63 | 64 | -------------------------------------------------------------------------------- /Commands/Un-comment selection.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | if ENV['TM_SELECTION'] =~ /^\d*$/ 11 | # Nothing selected 12 | require ENV['TM_SUPPORT_PATH'] + '/lib/exit_codes' 13 | TextMate::exit_discard 14 | end 15 | 16 | STDIN.each_line do |line| 17 | if line =~ /^(\s*#[ ])/ 18 | # Uncomment 19 | print line[Regexp.last_match[1].length..-1] 20 | else 21 | # Comment 22 | print '#' + ((line[0] == ' ') ? '' : ' ') + line 23 | end 24 | end 25 | input 26 | selection 27 | inputFormat 28 | text 29 | keyEquivalent 30 | @- 31 | name 32 | Un-/comment selection 33 | outputCaret 34 | interpolateByLine 35 | outputFormat 36 | text 37 | outputLocation 38 | replaceInput 39 | scope 40 | source.turtle, source.sparql 41 | uuid 42 | 1BAF8A19-B8BD-429C-ACCA-1BADC9345A26 43 | version 44 | 2 45 | 46 | 47 | -------------------------------------------------------------------------------- /Commands/Validate syntax.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | saveActiveFile 7 | command 8 | #!/usr/bin/env ruby18 -wKU 9 | 10 | require ENV['TM_SUPPORT_PATH'] + '/lib/textmate' 11 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui' 12 | require ENV['TM_SUPPORT_PATH'] + '/lib/escape' 13 | require ENV['TM_SUPPORT_PATH'] + '/lib/exit_codes' 14 | 15 | TextMate::require_cmd 'rapper' 16 | 17 | # Constants 18 | 19 | RAPPER_TPL = 'rapper --count -i guess \'%s\' 2>&1' 20 | FPATH = ENV['TM_FILEPATH'] 21 | FPATH_TOKEN = '<FPATH>' 22 | FURL = 'file://'+FPATH 23 | FURL_TOKEN = '<FURL>' 24 | 25 | # Helpers 26 | 27 | def html(snippet, type = nil) 28 | if type.nil? 29 | style = 'padding:3px 4px;background-color:#ffffff;color:#333333;' 30 | elsif type == 'err' 31 | style = 'padding:3px 4px;background-color:#cc4444;color:#ffffff;' 32 | elsif type == 'succ' 33 | style = 'padding:3px 4px;background-color:#118833;color:#ffffff;' 34 | end 35 | '<div style="font-size:1.1em; font-family:\'Lucida Grande\';'+style+'">'+snippet+'</div>' 36 | end 37 | 38 | def msg(type, msg, plain = true) 39 | TextMate::UI.tool_tip( 40 | html( (plain) ? '<p style="margin:0;padding:0;">'+msg+'</p>' : msg, type ), 41 | :format => :html, 42 | :transparent => true 43 | ) 44 | TextMate::exit_discard 45 | end 46 | 47 | def is_intro?(line) 48 | line =~ /^Parsing URI <FURL> with parser ([\w%]+)$/ 49 | end 50 | def is_summary?(line) 51 | 0 == (line =~ /^Parsing returned (\d+) triples?$/).nil? ? nil : $~[1].to_i 52 | end 53 | 54 | # Extractors 55 | 56 | def n_triples_parsed(lines) 57 | (lines[-1] =~ /^Parsing returned (\d+) triples$/).nil? ? nil : $~[1].to_i 58 | end 59 | 60 | def errors_from(lines) 61 | errs = { 'messages' => [], 'lines' => [] } 62 | lines.each do |line| 63 | next if (line =~ /^Error - (?:URI <FURL>:)?(\d+)?\s?- (.+)$/).nil? 64 | m = Regexp.last_match.captures 65 | if m[0].nil? 66 | # General error 67 | errs['messages'].push m[1] 68 | else 69 | # Line-bound error 70 | errs['lines'].push m 71 | end 72 | end 73 | return errs 74 | end 75 | 76 | # Here we go 77 | 78 | output = `#{RAPPER_TPL % FPATH}` 79 | unless not output.empty? 80 | msg 'err', 'Rapper terminated unexpectedly' 81 | exit 82 | end 83 | 84 | lines = output. 85 | sub(/^rapper:\s/, ''). # Strip line begins 86 | gsub(/\nrapper:\s/m, "\n"). 87 | gsub(/file\s#{FPATH}/, 'file '+FPATH_TOKEN). # Replace file paths with token 88 | gsub(/URI\s#{FURL}/, 'URI '+FURL_TOKEN). # Replace file URLs with token 89 | split("\n") 90 | 91 | if $?.to_i.equal? 0 92 | # Raptor didn't report errors, now find out what he wants to tell us 93 | if lines.length.equal? 2 94 | if is_intro? lines[0] and is_summary? lines[1] 95 | msg('succ', 'Syntax OK ('+n_triples_parsed(lines).to_s+' triples parsed)') 96 | end 97 | end 98 | # Dunno what else Raptor could tell us; just dump it out 99 | puts lines 100 | TextMate::exit_show_tool_tip 101 | else 102 | # Raptor reported errors, now interpret them 103 | errors = errors_from lines 104 | html = '' 105 | if errors['messages'].any? or errors['lines'].any? 106 | # There are obvious errors 107 | if errors['messages'].any? 108 | # Show misc error messages 109 | html += '<h2 style="color:#000000;margin:0 0 5px 0;font-size:1.2em;">General</h2><ul style="margin:0;padding:0 4px 0 20px;list-style-type:square;">' 110 | errors['messages'].each do |msg| 111 | html += '<li>'+msg+'</li>' 112 | end 113 | html += '</ul>' 114 | end 115 | if errors['lines'].any? 116 | # Extract error lines 117 | html += '<h2 style="color:#000000;margin:3px 0 5px 0;font-size:1.2em;">Dirty lines</h2><ul style="margin:0 0 3px 0;padding:0 4px 0 20px;list-style-type:square;">' 118 | errors['lines'].each do |msg| 119 | html += '<li>'+msg[0]+': '+msg[1]+'</li>' 120 | end 121 | html += '</ul>' 122 | end 123 | else 124 | html += '<h2 style="color:#000000;margin:0 0 5px 0;font-size:1.2em;">There are errors...</h2><ul style="margin:0;padding:0 4px 0 20px;list-style-type:square;">' 125 | lines.each do |line| 126 | html += '<li>'+htmlize(line)+'</li>' 127 | end 128 | html += '</ul>' 129 | end 130 | # Now show user the mess he caused 131 | msg 'err', html, false 132 | end 133 | 134 | input 135 | none 136 | inputFormat 137 | text 138 | keyEquivalent 139 | ^V 140 | name 141 | Validate syntax 142 | outputCaret 143 | afterOutput 144 | outputFormat 145 | html 146 | outputLocation 147 | toolTip 148 | scope 149 | source.turtle 150 | uuid 151 | 57E5DA96-6449-43DA-84FB-C3493D13FA5B 152 | version 153 | 2 154 | 155 | 156 | -------------------------------------------------------------------------------- /Commands/Visualize knowledge base.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env bash 9 | [[ -f "${TM_SUPPORT_PATH}/lib/bash_init.sh" ]] && . "${TM_SUPPORT_PATH}/lib/bash_init.sh" 10 | 11 | . "${TM_SUPPORT_PATH}/lib/html.sh" 12 | . "${TM_SUPPORT_PATH}/lib/webpreview.sh" 13 | 14 | # Prepare output window 15 | html_header "Visualization of \"$TM_FILENAME\"" "$FILE" 16 | SRC=${TM_FILENAME:-untitled.dot} 17 | DST="${TMPDIR:-/tmp}/dot_${SRC%.*}.pdf" 18 | ERR="${TMPDIR:-/tmp}/dot_errors" 19 | 20 | # Partytime 21 | if "${TM_RAPPER:-rapper}" -i turtle -o dot /dev/stdin \ 22 | -f 'resourceFill="#ff0000"' \ 23 | -f 'literalFill="#00ff00"' \ 24 | -f 'bnodeFill="#0000ff"' \ 25 | -f 'resourceBorder="#ffffff"' \ 26 | -f 'bnodeBorder="#ffffff"' \ 27 | -f 'literalBorder="#ffffff"' \ 28 | | sed "s/(Unknown)/${SRC%.*}/g" \ 29 | | "${TM_DOT:-dot}" -Tpdf -o "$DST" &>"$ERR"; then 30 | echo "<meta http-equiv='refresh' content='0; file://$DST'>" 31 | else 32 | pre <"$ERR" 33 | fi 34 | rm -f "$ERR" 35 | html_footer 36 | 37 | input 38 | document 39 | inputFormat 40 | text 41 | keyEquivalent 42 | @r 43 | name 44 | Visualize Knowledge Base 45 | outputCaret 46 | afterOutput 47 | outputFormat 48 | html 49 | outputLocation 50 | newWindow 51 | requiredCommands 52 | 53 | 54 | command 55 | dot 56 | locations 57 | 58 | /usr/local/bin/dot 59 | /opt/local/bin/dot 60 | /usr/bin/dot 61 | 62 | variable 63 | TM_DOT 64 | 65 | 66 | command 67 | rapper 68 | locations 69 | 70 | /usr/local/bin/rapper 71 | /opt/local/bin/rapper 72 | /usr/bin/rapper 73 | 74 | variable 75 | TM_RAPPER 76 | 77 | 78 | scope 79 | source.turtle 80 | semanticClass 81 | process.run.turtle 82 | uuid 83 | 2D08ACD4-99AF-46C6-B62A-FEE1CCB5A278 84 | version 85 | 2 86 | 87 | 88 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013–2015 Peter Geil 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Preferences/Completion SPARQL1_1.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Completion SPARQL1.1 7 | scope 8 | source.sparql 9 | settings 10 | 11 | completions 12 | 13 | SELECT 14 | ASK 15 | CONSTRUCT 16 | DESCRIBE 17 | FROM 18 | NAMED 19 | WHERE 20 | GRAPH 21 | DISTINCT 22 | REDUCED 23 | AS 24 | GROUP 25 | BY 26 | ASC 27 | DESC 28 | LIMIT 29 | UNION 30 | FILTER 31 | HAVING 32 | VALUES 33 | OPTIONAL 34 | SERVICE 35 | STR 36 | LANG 37 | LANGMATCHES 38 | DATATYPE 39 | BOUND 40 | IRI 41 | URI 42 | BNODE 43 | RAND 44 | ABS 45 | CEIL 46 | FLOOR 47 | ROUND 48 | CONCAT 49 | STRLEN 50 | UCASE 51 | LCASE 52 | ENCODE_FOR_URI 53 | CONTAINS 54 | STRSTARTS 55 | STRENDS 56 | STRBEFORE 57 | STRAFTER 58 | YEAR 59 | MONTH 60 | DAY 61 | HOURS 62 | MINUTES 63 | SECONDS 64 | TIMEZONE 65 | TZ 66 | NOW 67 | UUID 68 | STRUUID 69 | MD5 70 | SHA1 71 | SHA256 72 | SHA384 73 | SHA512 74 | COALESCE 75 | IF 76 | STRLANG 77 | STRDT 78 | sameTerm 79 | isIRI 80 | isURI 81 | isBLANK 82 | isLITERAL 83 | isNUMERIC 84 | COUNT 85 | SUM 86 | MIN 87 | MAX 88 | AVG 89 | SAMPLE 90 | GROUP_CONCAT 91 | true 92 | false 93 | DATA 94 | ADD 95 | MOVE 96 | COPY 97 | INSERT 98 | DELETE 99 | LOAD 100 | SILENT 101 | LOAD 102 | INTO 103 | CLEAR 104 | DEFAULT 105 | ALL 106 | CREATE 107 | DROP 108 | WITH 109 | USING 110 | BOUND 111 | COALESCE 112 | NOT EXISTS 113 | EXISTS 114 | REGEX 115 | SUBSTR 116 | REPLACE 117 | 118 | disableIndentCorrections 119 | 1 120 | foldingStartMarker 121 | [ \t]*([\[\(\{]|^(\s*\w*:\w|\<[^\>]+\>)(?=\b|\s*)|^#---$) 122 | foldingStopMarker 123 | [ \t]*([\]\)\}]|[.]\s*$|^\#/.*$) 124 | highlightPairs 125 | 126 | 127 | [ 128 | ] 129 | 130 | 131 | ( 132 | ) 133 | 134 | 135 | " 136 | " 137 | 138 | 139 | { 140 | } 141 | 142 | 143 | < 144 | > 145 | 146 | 147 | smartTypingPairs 148 | 149 | 150 | [ 151 | ] 152 | 153 | 154 | ( 155 | ) 156 | 157 | 158 | " 159 | " 160 | 161 | 162 | { 163 | } 164 | 165 | 166 | < 167 | > 168 | 169 | 170 | 171 | uuid 172 | 45C1C859-C069-4DEA-A1DF-2F9FB8E650A1 173 | 174 | 175 | -------------------------------------------------------------------------------- /Preferences/Completion: literal language tags.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | isDisabled 6 | 7 | name 8 | Completion: literal language tags 9 | scope 10 | L: constant.language.language_tag.turtle 11 | settings 12 | 13 | completions 14 | 15 | @en 16 | @en-us 17 | @en-gb 18 | @de 19 | @de-at 20 | @de-de 21 | 22 | 23 | uuid 24 | 09DBA542-1ED3-4D2B-BACC-072CDB2288E5 25 | 26 | 27 | -------------------------------------------------------------------------------- /Preferences/Completions literal types.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Completion: literal type 7 | scope 8 | L: storage.type.datatype.turtle 9 | settings 10 | 11 | comment 12 | I gave up. No elegant way to offer autocompletion for type annotation. (multiple scopes + scope completion = not possible 13 | completions 14 | 15 | ^^xsd:string 16 | ^^xsd:boolean 17 | ^^xsd:decimal 18 | ^^xsd:float 19 | ^^xsd:double 20 | ^^xsd:duration 21 | ^^xsd:dateTime 22 | ^^xsd:time 23 | ^^xsd:date 24 | ^^xsd:gYearMonth 25 | ^^xsd:gYear 26 | ^^xsd:gMonthDay 27 | ^^xsd:gDay 28 | ^^xsd:gMonth 29 | ^^xsd:hexBinary 30 | ^^xsd:base64Binary 31 | ^^xsd:anyURI 32 | ^^xsd:normalizedString 33 | ^^xsd:token 34 | ^^xsd:language 35 | ^^xsd:NMTOKEN 36 | ^^xsd:NMTOKENS 37 | ^^xsd:Name 38 | ^^xsd:NCName 39 | ^^xsd:ID 40 | ^^xsd:IDREF 41 | ^^xsd:IDREFS 42 | ^^xsd:ENTITY 43 | ^^xsd:ENTITIES 44 | ^^xsd:integer 45 | ^^xsd:nonPositiveInteger 46 | ^^xsd:negativeInteger 47 | ^^xsd:long 48 | ^^xsd:int 49 | ^^xsd:short 50 | ^^xsd:byte 51 | ^^xsd:nonNegativeInteger 52 | ^^xsd:unsignedLong 53 | ^^xsd:unsignedInt 54 | ^^xsd:unsignedShort 55 | ^^xsd:unsignedByte 56 | ^^xsd:positiveInteger 57 | 58 | 59 | uuid 60 | 16202143-1C61-4FE4-9FFB-EA45E7EB1942 61 | 62 | 63 | -------------------------------------------------------------------------------- /Preferences/Completions: XSD.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | isDisabled 6 | 7 | name 8 | Completions: XSD 9 | scope 10 | source.turtle 11 | settings 12 | 13 | completions 14 | 15 | string 16 | boolean 17 | decimal 18 | float 19 | double 20 | duration 21 | dateTime 22 | time 23 | date 24 | gYearMonth 25 | gYear 26 | gMonthDay 27 | gDay 28 | gMonth 29 | hexBinary 30 | base64Binary 31 | anyURI 32 | normalizedString 33 | token 34 | language 35 | NMTOKEN 36 | NMTOKENS 37 | Name 38 | NCName 39 | ID 40 | IDREF 41 | IDREFS 42 | ENTITY 43 | ENTITIES 44 | integer 45 | nonPositiveInteger 46 | negativeInteger 47 | long 48 | int 49 | short 50 | byte 51 | nonNegativeInteger 52 | unsignedLong 53 | unsignedInt 54 | unsignedShort 55 | unsignedByte 56 | positiveInteger 57 | xsd:string 58 | xsd:boolean 59 | xsd:decimal 60 | xsd:float 61 | xsd:double 62 | xsd:duration 63 | xsd:dateTime 64 | xsd:time 65 | xsd:date 66 | xsd:gYearMonth 67 | xsd:gYear 68 | xsd:gMonthDay 69 | xsd:gDay 70 | xsd:gMonth 71 | xsd:hexBinary 72 | xsd:base64Binary 73 | xsd:anyURI 74 | xsd:normalizedString 75 | xsd:token 76 | xsd:language 77 | xsd:NMTOKEN 78 | xsd:NMTOKENS 79 | xsd:Name 80 | xsd:NCName 81 | xsd:ID 82 | xsd:IDREF 83 | xsd:IDREFS 84 | xsd:ENTITY 85 | xsd:ENTITIES 86 | xsd:integer 87 | xsd:nonPositiveInteger 88 | xsd:negativeInteger 89 | xsd:long 90 | xsd:int 91 | xsd:short 92 | xsd:byte 93 | xsd:nonNegativeInteger 94 | xsd:unsignedLong 95 | xsd:unsignedInt 96 | xsd:unsignedShort 97 | xsd:unsignedByte 98 | xsd:positiveInteger 99 | 100 | 101 | uuid 102 | 8B318FC3-9916-4E31-B47A-E8318EF0FC29 103 | 104 | 105 | -------------------------------------------------------------------------------- /Preferences/Symbol list: Hidden.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Symbol list: Hidden 7 | scope 8 | source.turtle 9 | settings 10 | 11 | showInSymbolList 12 | 0 13 | 14 | uuid 15 | 3E82C3D4-DE36-4A89-A739-588484F3EE74 16 | 17 | 18 | -------------------------------------------------------------------------------- /Preferences/Symbol list: Shown.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Symbol list: Shown 7 | scope 8 | source.turtle meta.spec.directive.turtle 9 | settings 10 | 11 | disableIndentCorrections 12 | 1 13 | showInSymbolList 14 | 1 15 | 16 | uuid 17 | 688E424B-BD82-40BE-BBFE-6131AC881D77 18 | 19 | 20 | -------------------------------------------------------------------------------- /Preferences/Turtle settings.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Turtle settings 7 | scope 8 | source.turtle 9 | settings 10 | 11 | disableIndentCorrections 12 | 1 13 | foldingStartMarker 14 | \s*([\[\(\{]|^(\s*\w*:\w|\<[^\>]+\>)(?=\b|\s*)) 15 | foldingStopMarker 16 | \s*([\]\)\}]|[.]\s*$) 17 | highlightPairs 18 | 19 | 20 | [ 21 | ] 22 | 23 | 24 | ( 25 | ) 26 | 27 | 28 | " 29 | " 30 | 31 | 32 | { 33 | } 34 | 35 | 36 | < 37 | > 38 | 39 | 40 | smartTypingPairs 41 | 42 | 43 | [ 44 | ] 45 | 46 | 47 | ( 48 | ) 49 | 50 | 51 | " 52 | " 53 | 54 | 55 | { 56 | } 57 | 58 | 59 | < 60 | > 61 | 62 | 63 | 64 | uuid 65 | 4DCE5FA1-8BBE-4A24-8507-A21AAD9E03BD 66 | 67 | 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # turtle.tmbundle 2 | --------------------------------------------------------------------- 3 | 4 | Totally awesome bundle for Turtle – the terse RDF triple language. 5 | 6 | It consists of: 7 | 8 | + Language grammar for Turtle and SPARQL 1.1 9 | + Powerful auto-completion (live-aggregated) 10 | + Documentation for classes and roles/properties at your fingertips (live-aggregated) 11 | + Interactive SPARQL query scratchpad 12 | + Some snippets (prefixes and document skeleton) 13 | + Solid syntax validation 14 | + Commands for instant graph visualization of a knowledge base (requires Graphviz and Raptor) 15 | + Automatic removal of unused prefixes 16 | + Conversion between all common RDF formats 17 | 18 | See [Screenshots](#screenshots) 19 | 20 | __NOTE: If the HTML output of this GitHub-flavored Markdown document looks broken, please visit [https://github.com/peta/turtle.tmbundle/blob/master/README.md] to read the original version__ 21 | 22 | ## Language grammar 23 | 24 | The language grammar now covers the official W3C parser spec (as proposed in the latest CR released on Feb 19th 2013). However, there are still one/two particularities that differ, but you shouldn't notice them during your daily work. In the case you notice some weird behaviour (most obvious sign: broken syntax highlighting), please file a bug in the [project's issue tracker](https://github.com/peta/turtle.tmbundle/issues "Here at GitHub"). 25 | 26 | The language grammar also recognizes keywords and builtin functions from the latest SPAR[QU]L 1.1 language specification. Further there is basic autocompletion (`⌥ + ⎋`) for the aforementioned. 27 | 28 | ## Powerful auto-completion 29 | 30 | The Turtle bundle offers auto-completion at two levels: 31 | 32 | __NOTE: *When determining IRIs associated with a given prefix name, local prefix declarations always have precedence over those given by prefix.cc. So when you mess up IRIs in your @prefix directives, auto-completion might not work as expected.*__ 33 | 34 | ### Auto-completion for prefix directives 35 | 36 | When you invoke the `Autocomplete` command (`⌥ + ⎋`) within the scope of a prefix directive (right after `@prefix` or `PREFIX`), the Turtle bundle fetches a list of all prefixes registered at [prefix.cc](http://prefix.cc) and displays them nicely in a auto-complete dropdown box. Once you have chosen an and confirmed your selection, the prefix directive is automagically updated with the prefix and its according URI. (Note: the fetched data is locally cached for 24h) 37 | 38 | __NOTE: *Auto-completion for prefix declarations is case-insensitive*__ 39 | 40 | ### Auto-completion for the local part of prefixed name IRIs 41 | 42 | When you invoke the `Autocomplete` command (`⌥ + ⎋`) within the scope of a prefixed name (e.g. right after `my:` or at `my:a...`), the Turtle bundle determines the actual URI that is abbreviated by the prefixed namespace and checks if there is a machine readable Vocabulary/Ontology document available (currently only RDF/S and OWL documents in the XML serialization format are supported -- but with known issues). When one is found, it is live-aggregated and all of its Classes and Roles/Properties are extracted (along with their documentation) and nicely presented in a auto-complete dropdown box. (Note: the fetched data is locally cached for 24h) 43 | 44 | __NOTE: *Auto-completion for prefixed names is case-sensitive*__ 45 | 46 | ### Known issues 47 | 48 | For now, the Turtle bundle relies on [prefix.cc](http://prefix.cc) for mapping prefixes to URIs (required for all live-aggregations). The problem however is, that the available listings contain only one IRI per prefix (the one with the highest ranking) and not every IRI offers a machine readable vocabulary/ontology representation, what in turn means that for certain prefixes no auto-completion data might be available. You can help to fix this, by visiting the according page at prefix.cc (URL scheme looks like `http://prefix.cc/`; without angle brackets ofc) and up/downvoting the according URIs. 49 | 50 | The automatic aggregation of machine-readable vocabulary/ontology descriptions is working in principle but still has some shortcomings. (See the Github issue tracker) I will overwork that part when I have some more spare time and/or the need just arises. When you're told that data for a given prefix was fetched (green tooltip after a few seconds of freeze) but you will see no autocompletion dropdown later on, it probably means that the aggregator script failed and/or the IRI could not redirect to resource in a compatible format. 51 | 52 | ## Documentation for classes, roles/properties and individuals 53 | 54 | When you invoke the `Documentation for Resource` command (`⌃ + H`) within the scope of a prefixed name IRI (e.g. `my:Dog`), the Turtle bundle looks up if there are any informal descriptions available (like description texts, HTTP URLs to human-readable docs, asf.) and if so, displays them to the user. (Note: the fetched data is locally cached for 24h) 55 | 56 | __NOTE: *That function also suffers from the issues outlined in the previous section.*__ 57 | 58 | ## Interactive SPARQL query scratchpad ## 59 | 60 | All (web-based) query forms that crossed by cursor had one thing in common – they suck(ed). Syntax highlighting? Efficient workflows (like trial-error-roundtripping)? Of course NOT. So I decided to add something similar to TextMate. The *Execute SPARQL Query* command may seem self-explaining, but it hides some important features: 61 | 62 | + first of all, it supports multiple sections in a single document 63 | + it is aware of custom magic comments types (called "markers") for 64 | + specifying different SPARQL Query/Update services (aka *endpoints*) 65 | + including/calling other section from within the same document 66 | + query results are nicely displayed together with the query log in a preview window 67 | 68 | Just press `⌘ + R` and your query will be executed. 69 | 70 | ### Multiple sections/snippets syntax 71 | 72 | You can have one document contain multiple (independent) sections. This is e.g. useful when developing complex queries where we usually follow an iterative approach. When running the `Execute SPARQL Query` command, it will automatically figure out what your intention is and act accordingly. It assumes that you will always do one of the following tasks: 73 | 74 | 1. Execute the whole document 75 | 2. Execute your current selection 76 | 3. Execute the section where your cursor is currently positioned in 77 | 78 | A simple document with multiple sections could look like this: 79 | 80 | ``` 81 | #QUERY 82 | #UPDATE 83 | 84 | PREFIX rdfs: 85 | PREFIX : 86 | 87 | INSERT DATA { :instanceA rdfs:label 'Human-readable label of instanceA'. } 88 | 89 | #--- 90 | PREFIX : 91 | SELECT (COUNT(?subj) AS ?n_subjs) 92 | WHERE { ?subj a :ClassA } 93 | 94 | #--- 95 | PREFIX : 96 | SELECT ?g 97 | WHERE { GRAPH ?g {} } 98 | ``` 99 | 100 | As you probably notice, multiple sections are separated with the marker string `#---` written on a separate line. 101 | 102 | ### Magic comment syntax for endpoints 103 | 104 | These magic comments have the following syntax: 105 | 106 | + `#QUERY 125 | #UPDATE 126 | PREFIX rdfs: \ 127 | PREFIX : | 128 | INSERT DATA { | http://example.com/tbox/update 129 | :ClassB a rdfs:Class; | 130 | rdfs:subClassOf :ClassA. | 131 | } / 132 | 133 | #--- 134 | #UPDATE 135 | PREFIX : \ 136 | INSERT DATA { | 137 | :instA a :ClassB; | http://example.com/abox/update 138 | rdfs:label 'Instance of ClassB'. | 139 | } / 140 | 141 | #--- 142 | PREFIX : \ 143 | SELECT (COUNT(?subj) AS ?n_subjs) | http://example.com/ds/query 144 | WHERE { ?subj a :ClassA } / 145 | 146 | #--- 147 | #QUERY 148 | SELECT DISTINCT ?s ?label \ 149 | WHERE { | http://dbpedia.org/sparql 150 | ?s ?o . | 151 | ?s rdfs:label ?label | 152 | } / 153 | 154 | #--- 155 | BASE \ 156 | SELECT DISTINCT ?s ?label | 157 | WHERE { | http://dbpedia.org/sparql 158 | ?s rdfs:label ?label | 159 | FILTER( CONTAINS( STR(?label), 'The Wire') ) | 160 | } / 161 | ``` 162 | 163 | ### Additional magic comment types 164 | 165 | #### Name your sections 166 | 167 | You can create a named section by adding a `#name= my-section` marker. Named sections can be included from other sections within your document. For more details see the next section: 168 | 169 | #### #INCLUDE 170 | 171 | By using Includes, you can reuse named sections all over the place. This way, it is possible to write typically used snippets once, and then just "call" them from anywhere else when needed. This is especially helpful for SPARQL beginners or when iteratively developing complex queries where one wants to see the effect of a previous query immediately. 172 | 173 | When executed, every included snippet is listed separately in the web preview window of TextMate. That way it is easy to track down issues with intermediate states (and not just only after all queries have finished). 174 | 175 | The order in which sections appear and are included in your document doesn't matter. So an included section doesn't have to be defined before the section it is included from. The following example shows a simple use-case: 176 | 177 | ``` 178 | #INCLUDE 179 | #INCLUDE 180 | #INCLUDE 181 | DELETE { ?s ?p ?o } 182 | WHERE { 183 | [] ?p ?o . 184 | ?s ?o . 185 | ?s ?p 'bnode 2' . 186 | FILTER( isBLANK( ?s ) ) 187 | } 188 | #INCLUDE 189 | 190 | #--- 191 | #name= insert-some-bnode 192 | PREFIX : 193 | INSERT DATA { 194 | [ a :MyClass ] :label 'bnode 1' . 195 | [ a :MyClass ] :label 'bnode 2' . 196 | [ a :MyClass ] :label 'bnode 3' . 197 | } 198 | 199 | #--- 200 | #name= drop-all 201 | #descr= Drop all graphs – both, the default graph and all named ones 202 | DROP ALL 203 | 204 | #--- 205 | #name= select-all-bnodes 206 | #descr= Selects all bnodes in the default graph 207 | SELECT DISTINCT * 208 | WHERE { 209 | ?s ?p ?o 210 | FILTER isBLANK(?s) 211 | } 212 | ``` 213 | 214 | ![Screenshot of SPARQL result preview window](./Support/img/screenshot-sparql.png "Screenshot of SPARQL result preview window") 215 | 216 | #### Notes 217 | 218 | There is also basic support for simple metadata properties in the following form: `#propname= some prop value`. It's the SPARQL pendant to jsdoc or phpdoc comments. However, beside section names an description texts I have no idea how this could be used. Do you? 219 | 220 | I have the vague idea of a pastebin for SPARQL in mind, where one can host reusable SPARQL snippets with support for parametrized SPARQL calls. What do you think about it? 221 | 222 | ## Snippets 223 | 224 | Right now the following snippets are included: 225 | 226 | + Basic document skeleton 227 | + "Smart" prefix/base directives (hit tab to see it work) 228 | + A set of basic prefix directives (Boring! The cool kids instead use the fancy auto-completion) 229 | 230 | ## Syntax validation 231 | 232 | You can trigger a syntax validation of your Turtle by pressing `CTRL + SHIFT + V`. In order to make use of syntax validation you must a have a working installation of the [Raptor RDF syntax library](http://librdf.org/raptor/). For detailed instructions about wiring up Raptor with Textmate, see the [#graph-visualization](section below). 233 | 234 | ![Screenshot of syntax validation error message](./Support/img/screenshot-syntaxval-error.png "Screenshot of syntax validation error message") 235 | 236 | ![Screenshot of syntax validation success message](./Support/img/screenshot-syntaxval-success.png "Screenshot of syntax validation success message") 237 | 238 | ## Graph visualization 239 | 240 | In order to use this functionality you need a working installation of [Graphviz](http://graphviz.org) (especially the dot command) and the [Raptor RDF syntax library](http://librdf.org/raptor/). When properly installed (locatable through PATHs) everything should work fine ootb. However, in some cases you must explicitly tell Textmate where to find them. You can do this by introducing two configuration variables (Textmate -> Preferences -> Variables): 241 | 242 | + `TM_DOT` absolute path to the dot binary (part of Graphviz) 243 | + `TM_RAPPER` absoluter path to the rapper binary (part of Raptor) 244 | 245 | By hitting `CMD + R` the active TTL document will be visualized on-the-fly in a Textmate HTML preview window. Because these preview windows are driven by Safari's WebKit rendering engine, PDF documents will be rendered right in-line. That way your "edit knowledge base --> visualize" workflow will be super intuitive and wont get interrupted by switching to separate PDF viewer app for viewing the visualization. 246 | 247 | By hitting `SHIFT + ALT + CMD + S` the active TTL document will be visualized and saved to a PDF document. 248 | 249 | ## Conversion between all common RDF formats 250 | 251 | In order to make use of the converter functionality, you must need a working installation of the [Raptor RDF syntax library](http://librdf.org/raptor/). For detailed instructions about wiring up Raptor with Textmate, see the [#graph-visualization](section above). 252 | 253 | ![Screenshot showing list of available target formats the user may choose from](./Support/img/screenshot-converter.png "Screenshot showing list of available target formats the user may choose from") 254 | 255 | ## Installation 256 | 257 | The Turtle bundle is now officially available through the Textate bundle installer (_Textmate -> Preferences -> Bundles_). However, it usually takes a few days until new releases are available through the bundle installer (make sure that you enabled 'Keep bundles updated' in the application preferences). If you know what you do, you can also install bundles (like Turtle) by hand. Just download/clone this repository, and place its root directory at `~/Library/Application Support/Avian/Bundles/Turtle.tmbundle`. That way it's kept distinct from bundles installed through the bundle installer. Textmate should notice the new bundle automatically; but when in doubt, just restart Textmate (`⌃ + ⌘ + Q`). 258 | 259 | ## Screenshots 260 | 261 | ![Screenshot of expanded bundle menu](./Support/img/screenshot-menu.png "Screenshot of expanded bundle menu") 262 | 263 | ![Screenshot showing SPARQL execution](./Support/img/screenshot-sparql-exec.png "Screenshot showing SPARQL execution") 264 | 265 | ![Screenshot editor showing auto-completion for resource identifier and documentation](./Support/img/screenshot-editor.png "Screenshot editor showing auto-completion for resource identifier and documentation") 266 | 267 | ![Screenshot of knowledge base visualization](./Support/img/screenshot-visu.png "Screenshot of knowledge base visualization") 268 | 269 | ## Meta 270 | 271 | Turtle.tmbundle was created by [Peter Geil](http://github.com/peta). Feedback is highly welcome – if you find a bug, have a feature request or simply want to contribute something, please let me know. Just visit the official GitHub repository at [https://github.com/peta/turtle.tmbundle](https://github.com/peta/turtle.tmbundle) and open an [issue](https://github.com/peta/turtle.tmbundle/issues). 272 | 273 | ### Please help making TextMate2 even more awesome! 274 | 275 | One of the features EVERY user could greatly benefit from, is a more powerful auto-completion feature. However, the implementation of such a feature takes a considerable amount of time. Unfortunately time is one of those goods, Allan (the creator of TextMate) and the other guy(s) from Macromates don't have enough from. So I had to idea to start a crowdfunding campaign to raising enough funds for working two months as full-time contributor to the TextMate 2 project. [Visit my campaign page and contribute!](http://www.indiegogo.com/projects/textmate-dialog2-sprint). 276 | 277 | ## Roadmap 278 | 279 | + Extract individuals (for both, autocompletion and documentation) 280 | + Work out documentation component 281 | + Display resource documentation as HTML text (with clickable links to official sources) in a notification window 282 | + Polish language grammar 283 | + Add additional caching layer for speeding up things (vanilla MacOS Ruby 1.8.7 has only sloooow REXML module) 284 | + Convert RDF/S and OWL documents from XML into Turtle and "link" resource identifiers to them, so that users can jump/navigate across all involved documents 285 | + To be fixed 286 | + Fix PN_LOCAL pattern so that semicolons inside POLs are marked up as terminators 287 | + Rewrite Turtle.tmBundle as nodejs module and publish as plugin for web-based code editors like Cloud9 and Atom -------------------------------------------------------------------------------- /Snippets/#INCLUDE .tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | #INCLUDE <$1> 7 | name 8 | #INCLUDE <uri> 9 | scope 10 | source.sparql 11 | tabTrigger 12 | minc 13 | uuid 14 | 944CC02E-E317-4FDF-9361-4A9877A8CB4A 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/#QUERY .tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | #QUERY <$1> 7 | name 8 | #QUERY <uri> 9 | scope 10 | source.sparql 11 | tabTrigger 12 | mqry 13 | uuid 14 | 6E33564E-A279-4BA3-A6FE-C0712026B55B 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/#UPDATE .tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | #UPDATE <$1> 7 | name 8 | #UPDATE <uri> 9 | scope 10 | source.sparql 11 | tabTrigger 12 | mup 13 | uuid 14 | 68FF6B12-FDDB-4C56-8B92-A820A1BBD930 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/BASE.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | BASE <${1:http://github.com/peta/turtle.tmbundle#}>$2 7 | name 8 | BASE 9 | scope 10 | source.sparql 11 | tabTrigger 12 | base 13 | uuid 14 | FC109A81-1B0F-4BB3-A756-26F0D5B98EDE 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/Base directive.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @base <${1:http://github.com/peta/turtle.tmbundle#}>.$2 7 | name 8 | @base Directive 9 | scope 10 | source.turtle 11 | tabTrigger 12 | base 13 | uuid 14 | 7EECA379-154D-49A2-9863-BB8F262ADA9F 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/Basic.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. 7 | @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>. 8 | @prefix xsd: <http://www.w3.org/2001/XMLSchema#>. 9 | @prefix $2: <${3:http://github.com/peta/turtle.tmbundle#}>. 10 | $1 11 | name 12 | Basic 13 | scope 14 | source.turtle 15 | tabTrigger 16 | pref_base 17 | uuid 18 | D7346290-2C45-4D52-BD1B-7DE7744A404E 19 | 20 | 21 | -------------------------------------------------------------------------------- /Snippets/DELETE.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | DELETE ${1:DATA }{ ${2:?s ?p ?o} }$3 7 | name 8 | DELETE 9 | scope 10 | source.sparql 11 | tabTrigger 12 | del 13 | uuid 14 | E2F1DED8-FDF1-4E5E-8CBD-EF5030B2498B 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/Document Skeleton.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. 7 | @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>. 8 | @prefix xsd: <http://www.w3.org/2001/XMLSchema#>. 9 | @prefix $2: <${3:http://github.com/peta/turtle.tmbundle#}>. 10 | 11 | # Author: ${TM_FULLNAME} 12 | # Created: `date +"%Y-%m-%d %H:%M"` 13 | # Description: ${4:N/A} 14 | 15 | $1 16 | name 17 | Document Skeleton 18 | scope 19 | source.turtle 20 | tabTrigger 21 | doc_skel 22 | uuid 23 | A436E557-CB60-4F4E-8EAA-BE129339E5BA 24 | 25 | 26 | -------------------------------------------------------------------------------- /Snippets/GRAPH.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | GRAPH ${1:?g} {${2: ${3:?s ?p ?o} }}$4 7 | name 8 | GRAPH 9 | scope 10 | source.sparql 11 | tabTrigger 12 | graph 13 | uuid 14 | 893B86AF-DD6B-4283-BA11-16955B1FD7A7 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/PREFIX.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | PREFIX ${1:${2:my}: <${3:http://github.com/peta/turtle.tmbundle#}>$4} 7 | name 8 | PREFIX 9 | scope 10 | source.sparql 11 | tabTrigger 12 | pref 13 | uuid 14 | ED8B6D2A-F402-4065-9A8F-5EED93826652 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/Prefix Directive.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | @prefix ${1:${2:my}: <${3:http://github.com/peta/turtle.tmbundle#}>.$4} 7 | name 8 | @prefix Directive 9 | scope 10 | source.turtle 11 | tabTrigger 12 | pref 13 | uuid 14 | 5556B1D0-1E0F-4299-B8F3-15C7C843B61D 15 | 16 | 17 | -------------------------------------------------------------------------------- /Snippets/SELECT.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | SELECT ${1:DISTINCT} { ${2:?s ?p ?o} }$3 7 | name 8 | SELECT 9 | scope 10 | source.sparql 11 | tabTrigger 12 | sel 13 | uuid 14 | AD2225AD-5AF2-437E-9D21-8ACB9C2598D2 15 | 16 | 17 | -------------------------------------------------------------------------------- /Support/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /Support/css/.gitignore: -------------------------------------------------------------------------------- 1 | .sass_cache/ -------------------------------------------------------------------------------- /Support/css/sparql-exec-preview.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Stylesheet for web preview of 'Execute SPARQL Query' output 3 | * 4 | * @author Peter Geil 5 | */ 6 | #tm_webpreview_content { 7 | margin: 28px 0 0 0 !important; 8 | counter-reset: qry-section; } 9 | 10 | .query-section { 11 | margin-bottom: 25px; } 12 | .query-section:before { 13 | counter-increment: qry-section; 14 | content: counter(qry-section); 15 | font-family: "Helvetica Neue"; 16 | font-weight: lighter; 17 | font-size: 78px; 18 | position: absolute; 19 | margin-top: 59px; 20 | right: 15px; 21 | color: rgba(0, 0, 0, 0.1); 22 | z-index: 999; 23 | pointer-events: none; 24 | -webkit-user-select: none; } 25 | .query-section .result { 26 | margin: 0 75px 0 14px; } 27 | .query-section .result table { 28 | border-color: #bbb; 29 | border-style: solid; 30 | border-width: 0 0 1px 0; } 31 | .query-section .result table tr:first-child { 32 | background-color: #ccc; 33 | color: #777; 34 | border: none; } 35 | .query-section .result table tr:first-child th { 36 | padding: 3px; 37 | font-family: "Helvetica Neue"; 38 | font-weight: 200; 39 | font-size: 17px; 40 | line-height: 1.4; 41 | color: #777; 42 | text-align: center; 43 | text-rendering: geometricPrecision; 44 | letter-spacing: 1px; 45 | border: 1px solid #ccc; } 46 | .query-section .result table tr { 47 | border-bottom-color: #ddd; } 48 | .query-section .result table tr:not(:first-child):hover { 49 | background-color: #efefef; } 50 | .query-section .result table tr td { 51 | padding: 2px 10px 3px 10px; } 52 | .query-section .header { 53 | font-family: "Lucida Grande"; } 54 | .query-section .header .code { 55 | font-weight: bold; 56 | font-size: 21px; 57 | float: left; 58 | margin: 0 20px 0 0; 59 | padding: 10px 0 10px 15px; } 60 | .query-section .header .message { 61 | margin: 0 20px 0 0; 62 | padding: 15px 0 0 15px; 63 | line-height: 1.1; 64 | color: #ddd; } 65 | .query-section .header .clear { 66 | clear: both; 67 | display: block; 68 | content: " "; 69 | width: 1px; 70 | height: 1px; } 71 | .query-section .header.success { 72 | background-color: #009262; 73 | color: #ffffff; } 74 | .query-section .header.error { 75 | background-color: #cc4444; 76 | color: #ffffff; } 77 | .query-section .query-log { 78 | margin: 0 0 12px 0; 79 | background-color: #ffffcc; } 80 | .query-section .query-log .result { 81 | padding-bottom: 7px; } 82 | .query-section .query-log .result pre { 83 | line-height: 0.6em; 84 | background-color: #fff; 85 | padding: 11px; 86 | border-left: 5px solid #ddd; 87 | tab-size: 2; 88 | -webkit-tab-size: 2; } 89 | .query-section .query-log .toggler { 90 | text-align: right; 91 | background-color: #ffffcc; } 92 | .query-section .query-log .toggler a { 93 | display: inline-block; 94 | padding: 4px 11px 6px 11px; 95 | border-bottom-left-radius: 6px; } 96 | -------------------------------------------------------------------------------- /Support/css/sparql-exec-preview.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Stylesheet for web preview of 'Execute SPARQL Query' output 3 | * 4 | * @author Peter Geil 5 | */ 6 | #tm_webpreview_content { 7 | margin: 28px 0 0 0 !important; 8 | counter-reset: qry-section; 9 | } 10 | 11 | .query-section { 12 | 13 | margin-bottom: 25px; 14 | 15 | &:before { 16 | counter-increment: qry-section; 17 | content: counter(qry-section); 18 | font-family: "Helvetica Neue"; 19 | font-weight: lighter; 20 | font-size: 78px; 21 | position: absolute; 22 | margin-top: 59px; 23 | right: 15px; 24 | color: rgba(0, 0, 0, 0.1); 25 | z-index: 999; 26 | pointer-events: none; 27 | -webkit-user-select: none; 28 | } 29 | &.odd! {} 30 | .result { 31 | margin: 0 75px 0 14px; 32 | 33 | table { 34 | border-color: #bbb; 35 | border-style: solid; 36 | border-width: 0 0 1px 0; 37 | 38 | tr:first-child { 39 | background-color: #ccc; 40 | color: #777; 41 | border: none; 42 | 43 | th { 44 | padding: 3px; 45 | font-family: "Helvetica Neue"; 46 | font-weight: 200; 47 | font-size: 17px; 48 | line-height: 1.4; 49 | color: #777; 50 | text-align: center; 51 | text-rendering: geometricPrecision; 52 | letter-spacing: 1px; 53 | border: 1px solid #ccc; 54 | } 55 | } 56 | 57 | tr { 58 | border-bottom-color: #ddd; 59 | &:not(:first-child):hover { 60 | background-color: #efefef; 61 | } 62 | 63 | td { 64 | padding: 2px 10px 3px 10px; 65 | } 66 | } 67 | } 68 | } 69 | .header { 70 | font-family: "Lucida Grande"; 71 | .code { 72 | font-weight: bold; 73 | font-size: 21px; 74 | float: left; 75 | margin: 0 20px 0 0; 76 | padding: 10px 0 10px 15px; 77 | } 78 | .message { 79 | margin: 0 20px 0 0; 80 | padding: 15px 0 0 15px; 81 | line-height: 1.1; 82 | color: #ddd; 83 | } 84 | .clear { 85 | clear: both; 86 | display: block; 87 | content: " "; 88 | width: 1px; 89 | height: 1px; 90 | } 91 | &.success { 92 | background-color: #009262; 93 | color: #ffffff; 94 | } 95 | &.error { 96 | background-color: #cc4444; 97 | color: #ffffff; 98 | } 99 | } 100 | .query-log { 101 | margin: 0 0 12px 0; 102 | background-color: #ffffcc; 103 | .result { 104 | padding-bottom: 7px; 105 | pre { 106 | line-height: 0.6em; 107 | background-color: #fff; 108 | padding: 11px; 109 | border-left: 5px solid #ddd; 110 | tab-size: 2; 111 | -webkit-tab-size: 2; 112 | } 113 | } 114 | .toggler { 115 | text-align: right; 116 | background-color: #ffffcc; 117 | a { 118 | display: inline-block; 119 | padding: 4px 11px 6px 11px; 120 | border-bottom-left-radius: 6px; 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Support/img/item-icons/Languages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/Languages.png -------------------------------------------------------------------------------- /Support/img/item-icons/Macros.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/Macros.png -------------------------------------------------------------------------------- /Support/img/item-icons/Snippets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/Snippets.png -------------------------------------------------------------------------------- /Support/img/item-icons/Template Files.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/Template Files.png -------------------------------------------------------------------------------- /Support/img/item-icons/empty_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/empty_gray.png -------------------------------------------------------------------------------- /Support/img/item-icons/iconmaker.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/iconmaker.psd -------------------------------------------------------------------------------- /Support/img/item-icons/p_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/p_red.png -------------------------------------------------------------------------------- /Support/img/item-icons/question_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/question_gray.png -------------------------------------------------------------------------------- /Support/img/item-icons/upper_c_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/upper_c_green.png -------------------------------------------------------------------------------- /Support/img/item-icons/upper_d_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/upper_d_red.png -------------------------------------------------------------------------------- /Support/img/item-icons/upper_i_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/upper_i_blue.png -------------------------------------------------------------------------------- /Support/img/item-icons/upper_p_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/upper_p_gray.png -------------------------------------------------------------------------------- /Support/img/item-icons/upper_p_purple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/upper_p_purple.png -------------------------------------------------------------------------------- /Support/img/item-icons/upper_t_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/item-icons/upper_t_blue.png -------------------------------------------------------------------------------- /Support/img/screenshot-converter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/screenshot-converter.png -------------------------------------------------------------------------------- /Support/img/screenshot-editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/screenshot-editor.png -------------------------------------------------------------------------------- /Support/img/screenshot-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/screenshot-menu.png -------------------------------------------------------------------------------- /Support/img/screenshot-sparql-exec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/screenshot-sparql-exec.png -------------------------------------------------------------------------------- /Support/img/screenshot-sparql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/screenshot-sparql.png -------------------------------------------------------------------------------- /Support/img/screenshot-syntaxval-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/screenshot-syntaxval-error.png -------------------------------------------------------------------------------- /Support/img/screenshot-syntaxval-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/screenshot-syntaxval-success.png -------------------------------------------------------------------------------- /Support/img/screenshot-visu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/img/screenshot-visu.png -------------------------------------------------------------------------------- /Support/lib/extractor.xsl: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | instance 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | instance 53 | 54 | 55 | 56 | instance 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /Support/lib/sparql.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "net/http" 4 | require "uri" 5 | 6 | require ENV['TM_SUPPORT_PATH'] + '/lib/osx/plist' 7 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui' 8 | require ENV['TM_SUPPORT_PATH'] + '/lib/current_word' 9 | 10 | module Turtle 11 | module SPARQL 12 | 13 | # Tells what part of the SPARQL language the given query string makes use of (either :update or :query) 14 | # @return [Symbol] 15 | def self.which_type?(qry_text) 16 | (qry_text =~ /(INSERT|DELETE|LOAD|CLEAR|CREATE|DROP|WITH)/) ? :update : :query 17 | end 18 | 19 | # Helper function for raising errors 20 | def self.raise_error(level, title, msg, exit = true) 21 | TextMate::UI::alert(level, title, msg) 22 | TextMate::exit_discard if exit 23 | end 24 | 25 | # Helper function for finding a suitable endpoint 26 | # @return [String, NilClass] 27 | def self.get_endpoint(type, section) 28 | new_ep = section.first_endpoint(type) 29 | new_ep = section.parent.first_endpoint(section.from_line, :bottom_up, type) if new_ep.nil? 30 | # nothing found, check environment and finally ask user 31 | if new_ep.nil? 32 | # Check if an endpoint is set by an ENV variable 33 | if ENV['TM_SPARQL_'+type.to_s.upcase] 34 | new_ep = ENV['TM_SPARQL_'+type.to_s.upcase] 35 | # Ask user 36 | else 37 | new_ep = TextMate::UI::request_string( 38 | :title => 'Choose SPARQL Endpoint', 39 | :prompt => 'Please enter URL of SPARQL '+type.to_s.upcase+' Service') 40 | end 41 | new_ep = (new_ep.to_s.strip.empty?) ? nil : new_ep 42 | end 43 | new_ep 44 | end 45 | 46 | # Represents a SPARQL document and offers an API for accessing its sections and endpoint markers 47 | class Document 48 | 49 | SECTION_MARKER = /^#---$/ 50 | SECTION_PROP = /^#([a-z0-9.:_\-]+)=\s+(.+)$/ 51 | 52 | def initialize(content) 53 | @sections = [] 54 | @state = :idle 55 | @current = nil 56 | parse(content) 57 | end 58 | 59 | # Iterates over all sections contained by current document 60 | def each(&block) 61 | if block_given? 62 | @sections.each(&block) 63 | else 64 | @sections.to_enum 65 | end 66 | end 67 | 68 | # Gets +Section+ object that spans over then given line number 69 | # @return [Section,NilClass] 70 | def section_at_line(line_no) 71 | @sections.each do |s| 72 | return s if s.has_line_number?(line_no) 73 | end 74 | end 75 | alias_method :[], :section_at_line 76 | 77 | # Tells if current document contains section with given `name` 78 | # @return [Boolean] 79 | def has_section?(name) 80 | return false if name.nil? 81 | @sections.each do |s| 82 | return true if s.name == name 83 | end 84 | false 85 | end 86 | 87 | # Returns document section with given name 88 | # @return [Section,NilClass] 89 | def find_section(name) 90 | return if name.nil? 91 | @sections.each do |s| 92 | return s if s.name == name 93 | end 94 | end 95 | 96 | undef [] 97 | def [](line_no) 98 | return if line_no.nil? 99 | line_no = line_no.to_i 100 | @doc_lines[line_no] 101 | end 102 | 103 | # Returns the first endpoint found by applying the given parameters or `nil` 104 | # when no suitable endpoint was found. 105 | # 106 | # @paran [NilClass, Fixnum] line_no 107 | # @param [Symbol] strategy 108 | # @param [Symbol, NilClass] type 109 | # @return [NilClas, String] 110 | def first_endpoint(line_no = nil, strategy = :top_bottom, type = nil) 111 | return unless @sections.any? 112 | 113 | # Determine index of section where we start searching at 114 | if not line_no.nil? 115 | from_idx = @sections.index do |s| 116 | line_no.between? s.from_line, s.to_line 117 | end; return if from_idx.nil? 118 | else 119 | from_idx = (strategy === :top_bottom) ? 0 : @sections.count 120 | end 121 | 122 | # Build range 123 | case strategy 124 | when :top_bottom 125 | range = from_idx.upto(@sections.count) 126 | when :bottom_up 127 | range = from_idx.downto(0) 128 | else 129 | return 130 | end 131 | 132 | # And scan it 133 | range.each do |idx| 134 | ep_marker = @sections.at(idx).first_endpoint(type) 135 | return ep_marker if (type.nil? or not ep_marker.nil?) 136 | end 137 | end 138 | 139 | def inspect() 140 | str = "Document contains #{@sections.count} sections(s)\n\n" 141 | @sections.each {|s| str += s.inspect + "\n\n--------------------\n\n" } 142 | return str 143 | end 144 | 145 | private 146 | 147 | # Parses the given document string 148 | # @param [String] doc_str 149 | def parse(doc_str) 150 | return unless @state === :idle 151 | @state = :in_doc 152 | # Begin document parsing 153 | doc_lines = doc_str.lines.map(&:chomp) 154 | doc_lines.each_with_index do |line,no| 155 | case @state 156 | when :in_doc 157 | begin_section(no) 158 | @state = :in_sect 159 | redo 160 | when :in_sect 161 | # 1. scan for magic comments 162 | case line 163 | when SECTION_PROP 164 | # It's a section property 165 | name = Regexp.last_match[1] 166 | value = Regexp.last_match[2] 167 | found_property name, value 168 | when SECTION_MARKER 169 | # Section ends here 170 | end_section([0, no-1].max) # (more precisely: in the previous before) 171 | @state = :in_doc 172 | else 173 | # Just add line to current section 174 | found_line line 175 | end 176 | else 177 | break 178 | end 179 | end; if @state == :in_sect 180 | # Close remaining section 181 | end_section(doc_lines.count - 1) 182 | @state = :in_doc 183 | end 184 | # Shutdown 185 | @state = :idle 186 | end 187 | 188 | # Start new document section 189 | # @param [Fixnum] line_no 190 | def begin_section(line_no) 191 | return unless @state === :in_doc 192 | @current = Section.new(self, line_no) 193 | end 194 | 195 | # Handle the line of code found by the parser 196 | # @param [String] line 197 | def found_line(line) 198 | return unless @state === :in_sect 199 | @current << line 200 | end 201 | 202 | # Handle the sectin property found by the parser 203 | # @param [String] name 204 | # @param [String] value 205 | def found_property(name, value) 206 | return unless @state === :in_sect 207 | @current.properties[name] = value 208 | end 209 | 210 | # Finalize current document section and return it 211 | # @return [Turtle::SPARQL::Section] 212 | def end_section(line_no) 213 | return unless @state === :in_sect 214 | sect = @current 215 | sect.freeze(line_no) 216 | @sections << sect unless sect.empty? 217 | @current = nil 218 | return sect 219 | end 220 | 221 | end # Document 222 | 223 | 224 | # Represents a document section and offers an API for accessing 225 | # its metadata, queries, markers and (specialized marker) endpoints 226 | class Section 227 | 228 | MARKER_PATTERN = /^#[A-Z]+[^=]?/ 229 | 230 | attr_reader :lines, :properties, :from_line, :to_line, :parent 231 | 232 | def initialize(parent_doc, from_line, lines = []) 233 | @lines = lines.to_a 234 | @parent = parent_doc 235 | @properties = {} 236 | @from_line = from_line.to_i 237 | @to_line = nil 238 | @queries = [[]] 239 | end 240 | 241 | # Tells if current section spans over given line number 242 | # @return [Boolean] 243 | def has_line_number?(num) 244 | num.between? @from_line, @to_line 245 | end 246 | 247 | # Finishes the current section and does postprocessing 248 | def freeze(to_line) 249 | @to_line = to_line.to_i 250 | @lines.each do |line| 251 | if line =~ MARKER_PATTERN and (marker = Marker.from(line)) 252 | if @queries[-1].is_a? Array 253 | # Flatten last query and clean up 254 | last_qry = @queries[-1].join("\n") 255 | if last_qry.strip.empty? 256 | @queries.slice!(-1) 257 | else 258 | @queries[-1] = last_qry 259 | end 260 | end 261 | # Add marker and new array for ordinary lines of text 262 | @queries << marker 263 | @queries << [] 264 | else 265 | # Add line to current query 266 | @queries[-1] << line unless line.strip.empty? 267 | end 268 | end 269 | unless @queries[-1].is_a? Marker 270 | # Flatten last query and clean up 271 | last_qry = @queries[-1].join("\n") 272 | if last_qry.strip.empty? 273 | @queries.slice!(-1) 274 | else 275 | @queries[-1] = last_qry 276 | end 277 | end 278 | super() 279 | end 280 | 281 | # Name of current section 282 | # return [String,NilClass] 283 | def name 284 | @properties['name'] 285 | end 286 | 287 | # Tells whether current section is empty 288 | # @return [Boolean] 289 | def empty? 290 | @lines.empty? and @properties.empty? 291 | end 292 | 293 | def each(&block) 294 | @queries.each(&block) 295 | end 296 | 297 | # Iterates over all +Markers+ contained in current section 298 | def each_marker(&block) 299 | markers = @queries.select {|qry| qry.is_a? Marker } 300 | (block_given?) ? markers.each(&block) : markers.to_enum 301 | end 302 | 303 | # Iterates over all endpoint +Markers+ contained in current section 304 | def first_endpoint(type = nil) 305 | @queries.each do |q| 306 | return q.value if q.is_a?(Marker) and (type.nil? or q.type_of?(type)) 307 | end 308 | nil 309 | end 310 | 311 | # Iterates over all queries contained in current +Section+ object 312 | def each_query(&block) 313 | return enum_for(:each_query) unless block_given? 314 | @queries.each do |qry| 315 | if qry.is_a? Marker 316 | if qry.type_of? :include 317 | # Include other section 318 | include_name = qry.value 319 | # Prevent recursion 320 | next unless include_name != self.name 321 | # Tell user when he tries to include a non-existing section 322 | unless @parent.has_section? include_name 323 | SPARQL.raise_error :critical, 'Index error', "No section with name '#{include_name}' found. Inclusion inside section '#{self.name}' failed." 324 | end 325 | # Evaluate inclusion 326 | @parent.find_section(include_name).each_query(&block) 327 | end 328 | else 329 | # Return query code 330 | block.call(qry) 331 | end 332 | end 333 | end 334 | 335 | def <<(line) 336 | @lines << line 337 | end 338 | 339 | def [](idx) 340 | @lines[idx] 341 | end 342 | 343 | def to_s 344 | @lines.join("\n") 345 | end 346 | 347 | def inspect() 348 | dump = ["BEGIN SECTION DUMP (#{from_line}–#{to_line})"] 349 | dump << "========\nPROPERTIES\n=========" 350 | if @properties.any? 351 | @properties.each do |k,v| 352 | dump << "'#{k}': '#{v}'" 353 | end 354 | else 355 | dump << 'NO PROPS AVAILABLE' 356 | end 357 | dump << "========\nMARKERS\n=========" 358 | dump += self.each_marker.map {|m| m.inspect } 359 | dump << "========\nQUERIES (#{@queries.count})\n=========" 360 | dump += @queries.map {|q| q.inspect } 361 | dump << "========\nCONTENT\n=========" 362 | dump += @lines 363 | dump << "\n\nEND SECTION DUMP\n" 364 | return dump.join("\n") 365 | end 366 | end # Section 367 | 368 | 369 | # A +Marker+ is a processing instruction embedded as magic comment. The +Marker+ 370 | # class simply encapsulates the marker name (aka its `type`) and the according 371 | # value. 372 | class Marker 373 | @@known_types = [:query, :update, :include] 374 | 375 | # Kind of factory method that tries to create a +Marker+ object from the given 376 | # line of query code. Returns +NilClass+ when creation fails. 377 | # @return [Turtle::SPARQL::Marker, NilClass] 378 | def self.from(line) 379 | types = @@known_types.map {|t| t.to_s.upcase }.join('|') 380 | if line =~ /^#(#{types})\s+<([^>]+)>\s*$/ 381 | return self.new(Regexp.last_match[1].downcase.to_sym, Regexp.last_match[2]) 382 | end 383 | end 384 | 385 | attr_reader :type, :value 386 | 387 | def initialize(type, value) 388 | @type = type 389 | @value = value 390 | end 391 | 392 | # Tells whether the current +Marker+ object is of the given `type` 393 | # @return [Boolean] 394 | def type_of?(sym) 395 | @type === sym 396 | end 397 | end # Marker 398 | 399 | end # SPARQL 400 | end # Turtle 401 | -------------------------------------------------------------------------------- /Support/lib/turtle.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "net/http" 4 | require "uri" 5 | require "yaml" 6 | require "rexml/document" 7 | include REXML 8 | 9 | require ENV['TM_SUPPORT_PATH'] + '/lib/osx/plist' 10 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui' 11 | require ENV['TM_SUPPORT_PATH'] + '/lib/current_word' 12 | 13 | module Turtle 14 | # BEGIN MODULE 15 | 16 | DEBUG = false 17 | SUPPORT_DIR = ENV['TM_BUNDLE_SUPPORT'] 18 | CACHE_DIR = "#{ENV['TM_BUNDLE_SUPPORT']}/cache" 19 | CACHE_LIFETIME = 60*60*24 20 | IMG_DIR = "#{ENV['TM_BUNDLE_SUPPORT']}/img" 21 | ICONS = { 22 | "Prefix" => "#{IMG_DIR}/item-icons/p_red.png", 23 | "Rsc_Class" => "#{IMG_DIR}/item-icons/upper_c_green.png", 24 | "Rsc_Prop" => "#{IMG_DIR}/item-icons/upper_p_purple.png", 25 | "Rsc_Instance" => "#{IMG_DIR}/item-icons/upper_i_blue.png", 26 | "Rsc_Datatype" => "#{IMG_DIR}/item-icons/upper_d_red.png", 27 | "Rsc_Unknown" => "#{IMG_DIR}/item-icons/question_gray.png", 28 | "Unknown" => "#{IMG_DIR}/item-icons/empty_gray.png" 29 | } 30 | 31 | def Turtle.resolve_URI(of_prefix, fpath) 32 | # Try to determine the IRI associated with prefix in current document 33 | if not fpath.nil? and File.exists? fpath 34 | cmd = <<-'CMD' 35 | grep -E '@prefix %s: <([^\>]+)>\.' '%s' | sed -e 's/^[^<]*\<\([^\>]*\)\>.*$/\1/' 36 | CMD 37 | uri = `#{cmd % [of_prefix, fpath]} ` 38 | uri = uri.split("\n").first || '' 39 | if (uri =~ URI::regexp).nil? 40 | # Invalid URI returned => ignore it 41 | uri = nil 42 | end 43 | else 44 | # User didn't save the newly created file he is working with 45 | # => ignore prefix directives and use the IRI prefix.cc gave us 46 | uri = nil 47 | end 48 | return uri 49 | end 50 | 51 | # In order to make Dialog2 display custom icons in front of 52 | # list items, they must be explicitly "registered" first. This isn't obvious. 53 | `"$DIALOG" images --register #{e_sh ICONS.to_plist}` 54 | 55 | class Prefixes 56 | PREFIX_FPATH = "#{CACHE_DIR}/prefixes.yml" 57 | PREFIX_CC_URL = "http://prefix.cc/popular/all.file.txt" 58 | 59 | def Prefixes.get_all(force_reload = false) 60 | if force_reload or ((not File.exists? PREFIX_FPATH) or (Time.now - File.mtime(PREFIX_FPATH)) > CACHE_LIFETIME) 61 | # Cache file older than 24h => reload 62 | File.open(PREFIX_FPATH, "w") do |f| 63 | YAML::dump(download(), f) 64 | end 65 | end 66 | f = File.open(PREFIX_FPATH, "r") 67 | prefixes = YAML::load(f) 68 | f.close 69 | return prefixes 70 | end 71 | 72 | def Prefixes.lookup(pref) 73 | prefixes = get_all() 74 | prefixes.has_key?(pref) ? prefixes[pref] : nil 75 | end 76 | 77 | def Prefixes.download 78 | prefixes = {} 79 | url = URI.parse(PREFIX_CC_URL) 80 | http = Net::HTTP.new(url.host, url.port) 81 | resp = http.request(Net::HTTP::Get.new(url.request_uri)) 82 | if ("200" != resp.code or "text/plain" != resp.content_type) 83 | return prefixes 84 | end 85 | resp.body.each_line do |line| 86 | frags = line.split("\t") 87 | if not frags[0].start_with? '#' 88 | # Exclude EOL byte 89 | prefixes[frags[0]] = frags[1][0..-2] 90 | end 91 | end 92 | prefixes 93 | end 94 | end 95 | 96 | class Model 97 | # TODO: Introduce additional caching layer for public API? 98 | 99 | XSL_FPATH = SUPPORT_DIR+'/lib/extractor.xsl' 100 | MODEL_FPATH_TPL = CACHE_DIR+'/%s.xml' 101 | CMD_TPL = <<-SH 102 | bash; 103 | set -o pipefail; 104 | curl -s -L -A 'Turtle.tmBundle' -H 'Accept: application/rdf+xml, application/owl+xml' '%s' \ 105 | | xsltproc --stringparam 'base-uri' '%s' '%s' - >'%s' 2>/dev/null 106 | SH 107 | 108 | attr_accessor :prefix, :uri 109 | 110 | def initialize(prefix, uri = nil, force_reload = false) 111 | @prefix, @uri = prefix, uri 112 | if @uri.nil? 113 | @uri = Prefixes.lookup(@prefix) 114 | end 115 | @loaded = false 116 | # Load model 117 | if not @uri.nil? 118 | fpath = MODEL_FPATH_TPL % mk_filename 119 | # Dummy file is used to keep track of vocabs/ontos 120 | # for which no machine readable representation exists. 121 | # That way we don't try to fetch useless data over and over again 122 | fpath_dummy = fpath + '.na' 123 | # Check if cache should be re-/generated 124 | if force_reload or not (File.file? fpath_dummy and (Time.now - File.mtime(fpath_dummy)) < CACHE_LIFETIME) 125 | (File.unlink fpath_dummy) rescue 'IGNORE' 126 | if force_reload or 127 | ((not File.file? fpath) or 128 | (Time.now - File.mtime(fpath)) > CACHE_LIFETIME or 129 | File.size(fpath).zero?) 130 | if system "#{CMD_TPL % [@uri, @uri, XSL_FPATH, fpath]}" 131 | # Cache successfully generated => inform user 132 | TextMate::UI.tool_tip "

Resources for prefix #{@prefix}: sucessfully extracted", :format => 'html', :transparent => true 133 | else 134 | # No suitable machine readable representation available 135 | # => create dummy file 136 | `touch '#{fpath_dummy}'` 137 | # And inform user 138 | TextMate::UI.tool_tip <<-HTML, :format => :html, :transparent => true 139 |

No autocompletion for current prefix available 140 | HTML 141 | end 142 | end 143 | end 144 | if File.file? fpath and File.size(fpath).nonzero? 145 | @xml = Document.new(File.open(fpath, 'r')) 146 | @loaded = true 147 | end 148 | end 149 | end 150 | 151 | def to_s 152 | '%s: <%s>' % [@prefix, @uri] 153 | end 154 | 155 | def available? 156 | return @loaded 157 | end 158 | 159 | # Return Resource element with given identifier 160 | def resource(id) 161 | XPath.first(@xml, "//resource[@id='#{id}']") 162 | end 163 | 164 | # Return all Resource defined in current Model 165 | def resources(type = 'all') 166 | return nil if not available? 167 | filter = (type == 'all') ? '' : "[@type='#{type}']" 168 | XPath.match(@xml, "//resource#{filter}[@id]") 169 | end 170 | 171 | def explain(id) 172 | return nil if not available? 173 | doc = {} 174 | @xml.each_element("/model/resource[@id='#{id}']/*") do |el| 175 | doc[el.name] = el.text 176 | if 'description' == el.name 177 | el.attributes.each { |k,v| doc[k] = v } 178 | end 179 | end 180 | return doc 181 | end 182 | 183 | private 184 | 185 | def mk_filename 186 | (@prefix+'_'+@uri). 187 | gsub(/[^\w\s_-]+/, ''). 188 | gsub(/(^|\b\s)\s+($|\s?\b)/, '\\1\\2'). 189 | gsub(/\s+/, '_') 190 | end 191 | 192 | end 193 | 194 | # END MODULE 195 | end 196 | -------------------------------------------------------------------------------- /Support/textmate-runner/proxy-installer.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | LREG='/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister' 4 | CWD="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 5 | 6 | echo "Started proxy-installer.sh in working directory: '$CWD'" 7 | 8 | if [[ "$1" == "install" ]]; then 9 | $LREG -r -v -f "$CWD/runner" 10 | echo "Installed. Terminating" 11 | elif [[ "$1" == "uninstall" ]]; then 12 | $LREG -r -v -u "$CWD/runner" 13 | echo "Uninstalled. Terminating" 14 | else 15 | echo "Usage: proxy-installer.sh (install | uninstall)" 16 | exit 1 17 | fi -------------------------------------------------------------------------------- /Support/textmate-runner/runner/TextMate2 (TTL:SPARQL).app/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | TextMate2 (TTL/SPARQL) 9 | CFBundleDocumentTypes 10 | 11 | 12 | CFBundleTypeIconFile 13 | Turtle 14 | CFBundleTypeExtensions 15 | 16 | ttl 17 | turtle 18 | 19 | CFBundleTypeOSTypes 20 | 21 | CFBundleTypeRole 22 | Editor 23 | CFBundleTypeName 24 | Turtle RDF document 25 | 26 | 27 | CFBundleTypeIconFile 28 | SPARQL 29 | CFBundleTypeExtensions 30 | 31 | sparql 32 | 33 | CFBundleTypeOSTypes 34 | 35 | CFBundleTypeRole 36 | Editor 37 | CFBundleTypeName 38 | SPARQL source file 39 | 40 | 41 | CFBundleExecutable 42 | TextMate Proxy 43 | CFBundleIdentifier 44 | name.petergeil.TextMateProxyRunner 45 | CFBundleInfoDictionaryVersion 46 | 6.0 47 | CFBundleName 48 | TextMate2 (TTL/SPARQL) 49 | CFBundlePackageType 50 | APPL 51 | CFBundleVersion 52 | 1.0 53 | LSMinimumSystemVersion 54 | 10.5.0 55 | LSUIElement 56 | 57 | NSHumanReadableCopyright 58 | © 2013 Peter Geil 59 | NSMainNibFile 60 | MainMenu 61 | NSPrincipalClass 62 | NSApplication 63 | CFBundleURLTypes 64 | 65 | 66 | CFBundleURLName 67 | SPARQL query URL 68 | CFBundleURLSchemes 69 | 70 | sparql 71 | 72 | 73 | 74 | CFBundleIconFile 75 | Application 76 | 77 | 78 | -------------------------------------------------------------------------------- /Support/textmate-runner/runner/TextMate2 (TTL:SPARQL).app/Contents/MacOS/TextMate Proxy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/textmate-runner/runner/TextMate2 (TTL:SPARQL).app/Contents/MacOS/TextMate Proxy -------------------------------------------------------------------------------- /Support/textmate-runner/runner/TextMate2 (TTL:SPARQL).app/Contents/Resources/AppSettings.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AcceptsFiles 6 | 7 | AcceptsText 8 | 9 | Creator 10 | Peter Geil 11 | DropSuffixes 12 | 13 | ttl 14 | sparql 15 | 16 | DropTypes 17 | 18 | Droppable 19 | 20 | InterpreterArgs 21 | 22 | -l 23 | 24 | OutputType 25 | None 26 | RemainRunningAfterCompletion 27 | 28 | RequiresAdminPrivileges 29 | 30 | ScriptArgs 31 | 32 | ScriptInterpreter 33 | /bin/bash 34 | Secure 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Support/textmate-runner/runner/TextMate2 (TTL:SPARQL).app/Contents/Resources/Application.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/textmate-runner/runner/TextMate2 (TTL:SPARQL).app/Contents/Resources/Application.icns -------------------------------------------------------------------------------- /Support/textmate-runner/runner/TextMate2 (TTL:SPARQL).app/Contents/Resources/MainMenu.nib/keyedobjects.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/textmate-runner/runner/TextMate2 (TTL:SPARQL).app/Contents/Resources/MainMenu.nib/keyedobjects.nib -------------------------------------------------------------------------------- /Support/textmate-runner/runner/TextMate2 (TTL:SPARQL).app/Contents/Resources/SPARQL.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/textmate-runner/runner/TextMate2 (TTL:SPARQL).app/Contents/Resources/SPARQL.icns -------------------------------------------------------------------------------- /Support/textmate-runner/runner/TextMate2 (TTL:SPARQL).app/Contents/Resources/Turtle.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peta/turtle.tmbundle/0782b476573a317917fb9b3bbe7e6a68abefa7a5/Support/textmate-runner/runner/TextMate2 (TTL:SPARQL).app/Contents/Resources/Turtle.icns -------------------------------------------------------------------------------- /Support/textmate-runner/runner/TextMate2 (TTL:SPARQL).app/Contents/Resources/script: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | for file in "$@" 4 | do 5 | echo "Opening $file" 6 | mate -a -r "$file" 7 | done -------------------------------------------------------------------------------- /Syntaxes/SPARQL.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | sparql 8 | 9 | keyEquivalent 10 | ^~S 11 | name 12 | SPARQL 13 | patterns 14 | 15 | 16 | include 17 | source.turtle#sparqlKeywords 18 | 19 | 20 | include 21 | source.turtle#sparqlFilterFns 22 | 23 | 24 | include 25 | source.turtle#sparqlLangConsts 26 | 27 | 28 | include 29 | source.turtle 30 | 31 | 32 | scopeName 33 | source.sparql 34 | uuid 35 | A66816FF-6EF0-46F7-8F67-438339EF61C9 36 | 37 | 38 | -------------------------------------------------------------------------------- /Syntaxes/Turtle.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | ttl 8 | turtle 9 | 10 | keyEquivalent 11 | ^~T 12 | name 13 | Turtle 14 | patterns 15 | 16 | 17 | include 18 | #turtleDoc 19 | 20 | 21 | repository 22 | 23 | ANON 24 | 25 | match 26 | \[[\u20\u9\uD\uA]*\] 27 | name 28 | meta.spec.ANON.turtle 29 | 30 | BLANK_NODE_LABEL 31 | 32 | captures 33 | 34 | 1 35 | 36 | name 37 | keyword.other.BLANK_NODE_LABEL.turtle 38 | 39 | 2 40 | 41 | name 42 | variable.other.BLANK_NODE_LABEL.turtle 43 | 44 | 45 | match 46 | (?x) 47 | (?<PN_CHARS_U>[\p{L}\p{M}_]){0} 48 | (?<PN_CHARS>[\p{L}\p{M}_\-0-9\u00B7\u0300-\u036F\u203F-\u2040]){0} 49 | (?<=\b|^)(_:) ((?:\g<PN_CHARS_U>|[0-9]) (?: (?:\g<PN_CHARS>|\.)* \g<PN_CHARS> )?) 50 | 51 | name 52 | meta.spec.BLANK_NODE_LABEL.turtle 53 | 54 | BlankNode 55 | 56 | name 57 | meta.spec.BlankNode.turtle 58 | patterns 59 | 60 | 61 | include 62 | #BLANK_NODE_LABEL 63 | 64 | 65 | include 66 | #ANON 67 | 68 | 69 | 70 | IRIREF 71 | 72 | captures 73 | 74 | 1 75 | 76 | name 77 | punctuation.definition.entity.begin.turtle 78 | 79 | 2 80 | 81 | name 82 | punctuation.definition.entity.end.turtle 83 | 84 | 85 | match 86 | (?x) (\<) (?:[^\x00-\x20\<\>\\\"\{\}\|\^`] | (?:\\u[0-9A-Fa-f]{4}|\\U[0-9A-Fa-f]{8}))* (\>) 87 | name 88 | entity.name.type.IRIREF.turtle 89 | 90 | PNAME_LN 91 | 92 | captures 93 | 94 | PNAME_NS 95 | 96 | name 97 | variable.other.PNAME_NS.turtle 98 | 99 | PN_LOCAL 100 | 101 | name 102 | support.variable.PN_LOCAL.turtle 103 | 104 | 105 | match 106 | (?x) 107 | (?<PNAME_NS> (?: (?: [\p{L}\p{M}] (?:(?:[\p{L}\p{M}_.\-0-9\u00B7\u0300-\u036F\u203F-\u2040])* [\p{L}\p{M}_\-0-9\u00B7\u0300-\u036F\u203F-\u2040] )? )? | _) \: ) 108 | (?<PN_LOCAL> 109 | (?# Should I include \p{M}?) 110 | (?: 111 | (?: [\p{L}_] | [:0-9] | %[0-9A-Fa-f]{2} | \\[_~\-!$&'\(\)*+=/?#@%.,;] ) 112 | (?: 113 | (?: [\p{L}_\-0-9\u00B7\u0300-\u036F\u203F-\u2040] | [:.] | \%[0-9A-Fa-f]{2} | \\ [_~\-!$&'\(\)*+=/?#@%.,;] )* 114 | (?: [\p{L}_\-0-9\u00B7\u0300-\u036F\u203F-\u2040] | : | \%[0-9A-Fa-f]{2} | \\ [_~\-!$&'\(\)*+=/?#@%.,;] ) 115 | ) 116 | )? 117 | ) 118 | 119 | name 120 | meta.spec.PNAME_LN.turtle 121 | 122 | PNAME_NS 123 | 124 | match 125 | (?x)((?<=\s|^|_)(?:[\p{L}\p{M}] (?:(?:[\p{L}\p{M}_.\-0-9\u00B7\u0300-\u036F\u203F-\u2040])* [\p{L}\p{M}_\-0-9\u00B7\u0300-\u036F\u203F-\u2040] )? )? : ) 126 | name 127 | variable.other.PNAME_NS.turtle 128 | 129 | PN_LOCAL 130 | 131 | match 132 | (?x)( 133 | (?: [\p{L}\p{M}] | [:0-9] | %[0-9A-Fa-f]{2} | \\[_~\-!$&'\(\)*+=/?#@%.,;] ) 134 | (?: 135 | (?:[\p{L}\p{M}_\-0-9\u00B7\u0300-\u036F\u203F-\u2040] | [:.] | %[0-9A-Fa-f]{2} | \\[_~\-!$&'\(\)*+=/?#@%.,;] )* 136 | (?:[\p{L}\p{M}_\-0-9\u00B7\u0300-\u036F\u203F-\u2040] | : | %[0-9A-Fa-f]{2} | \\[_~\-!$&'\(\)*+=/?#@%.,;] ) 137 | ) 138 | )? 139 | name 140 | support.variable.PN_LOCAL.turtle 141 | 142 | PrefixedName 143 | 144 | name 145 | meta.spec.PrefixedName.turtle 146 | patterns 147 | 148 | 149 | include 150 | #PNAME_LN 151 | 152 | 153 | include 154 | #PNAME_NS 155 | 156 | 157 | 158 | blankNodePropertyList 159 | 160 | begin 161 | \b(\[)\b 162 | captures 163 | 164 | 1 165 | 166 | name 167 | punctuation.terminator.blankNodePropertyList.turtle 168 | 169 | 170 | end 171 | \b(\])(?=\b|\s|[.;,]) 172 | name 173 | meta.spec.blankNodePropertyList.turtle 174 | patterns 175 | 176 | 177 | match 178 | ((?<=\s)[.;,](?=\b)) 179 | name 180 | punctuation.terminator.stmt.turtle 181 | 182 | 183 | include 184 | #literal 185 | 186 | 187 | include 188 | #blankNodePropertyList 189 | 190 | 191 | include 192 | #iri 193 | 194 | 195 | include 196 | #BlankNode 197 | 198 | 199 | include 200 | #collection 201 | 202 | 203 | match 204 | (?<=[ ])(a)(?=[ ]) 205 | name 206 | keyword.other.typeOf.turtle 207 | 208 | 209 | 210 | collection 211 | 212 | begin 213 | (\b\(\b) 214 | captures 215 | 216 | 1 217 | 218 | name 219 | punctuation.terminator.collection.turtle 220 | 221 | 222 | comment 223 | TODO: Make match patterns more stable 224 | end 225 | (\b\)\b) 226 | name 227 | meta.spec.collection.turtle 228 | patterns 229 | 230 | 231 | include 232 | #literal 233 | 234 | 235 | include 236 | #iri 237 | 238 | 239 | include 240 | #BlankNode 241 | 242 | 243 | include 244 | #collection 245 | 246 | 247 | match 248 | (?<=[ ])(a)(?=[ ]) 249 | name 250 | keyword.other.typeOf.turtle 251 | 252 | 253 | include 254 | #blankNodePropertyList 255 | 256 | 257 | 258 | directive 259 | 260 | begin 261 | (?i)(^(?=@prefix|@base|PREFIX|BASE)) 262 | end 263 | ($) 264 | name 265 | meta.spec.directive.turtle 266 | patterns 267 | 268 | 269 | begin 270 | ^(@prefix)(?=\s) 271 | beginCaptures 272 | 273 | 1 274 | 275 | name 276 | keyword.other.directive.prefix.turtle 277 | 278 | 279 | end 280 | (\.?)$ 281 | endCaptures 282 | 283 | 1 284 | 285 | name 286 | punctuation.terminator.directive.turtle 287 | 288 | 289 | name 290 | meta.spec.prefixID.turtle 291 | patterns 292 | 293 | 294 | include 295 | #IRIREF 296 | 297 | 298 | include 299 | #PNAME_NS 300 | 301 | 302 | 303 | 304 | begin 305 | ^(@base) 306 | beginCaptures 307 | 308 | 1 309 | 310 | name 311 | keyword.other.directive.base.turtle 312 | 313 | 314 | end 315 | (\.?)$ 316 | endCaptures 317 | 318 | 1 319 | 320 | name 321 | punctuation.terminator.directive.turtle 322 | 323 | 324 | name 325 | meta.spec.base.turtle 326 | patterns 327 | 328 | 329 | include 330 | #IRIREF 331 | 332 | 333 | 334 | 335 | begin 336 | ^(?i)(PREFIX)(?=\b) 337 | beginCaptures 338 | 339 | 1 340 | 341 | name 342 | keyword.other.directive.sparqlPrefix.turtle 343 | 344 | 345 | end 346 | $ 347 | name 348 | meta.spec.sparqlPrefix.turtle 349 | patterns 350 | 351 | 352 | include 353 | #IRIREF 354 | 355 | 356 | include 357 | #PNAME_NS 358 | 359 | 360 | 361 | 362 | begin 363 | ^(?i)(BASE)(?=\b) 364 | beginCaptures 365 | 366 | 1 367 | 368 | name 369 | keyword.other.directive.sparqlBase.turtle 370 | 371 | 372 | end 373 | $ 374 | name 375 | meta.spec.sparqlBase.turtle 376 | patterns 377 | 378 | 379 | include 380 | #IRIREF 381 | 382 | 383 | 384 | 385 | 386 | iri 387 | 388 | name 389 | meta.spec.iri.turtle 390 | patterns 391 | 392 | 393 | include 394 | #IRIREF 395 | 396 | 397 | include 398 | #PrefixedName 399 | 400 | 401 | 402 | literal 403 | 404 | name 405 | meta.spec.literal.turtle 406 | patterns 407 | 408 | 409 | match 410 | (?x) 411 | (?<=\s)[+-]? 412 | ( (?: \d+?\.?\d*[eE][+-]?\d+) | \d*\.\d+ | \d+) 413 | (?=[ ]*[,.;]?) 414 | 415 | name 416 | constant.numeric.turtle 417 | 418 | 419 | match 420 | (?<=\s)(true|false)(?=[ ]*[,.;]?) 421 | name 422 | constant.language.boolean.turtle 423 | 424 | 425 | name 426 | meta.spec.RDFLiteral.turtle 427 | patterns 428 | 429 | 430 | include 431 | #literal_triple 432 | 433 | 434 | include 435 | #literal_double 436 | 437 | 438 | include 439 | #literal_single 440 | 441 | 442 | 443 | 444 | 445 | literal_double 446 | 447 | captures 448 | 449 | 1 450 | 451 | name 452 | punctuation.definition.string.begin.turtle 453 | 454 | 2 455 | 456 | name 457 | punctuation.definition.string.end.turtle 458 | 459 | dt 460 | 461 | name 462 | storage.type.datatype.turtle 463 | 464 | lang 465 | 466 | name 467 | constant.language.language_tag.turtle 468 | 469 | 470 | match 471 | (?x) 472 | (")[^"\\]*(?:\\.[^"\\]*)*(") 473 | (?<lang>@(?:[a-z]{2}(?:-[a-z0-9]{2})*)?)? 474 | (?<dt>\^\^\w*:\w*|\<[^\>]+\>)? 475 | 476 | name 477 | string.quoted.double.turtle 478 | 479 | literal_single 480 | 481 | captures 482 | 483 | 1 484 | 485 | name 486 | punctuation.definition.string.begin.turtle 487 | 488 | 2 489 | 490 | name 491 | punctuation.definition.string.end.turtle 492 | 493 | dt 494 | 495 | name 496 | storage.type.datatype.turtle 497 | 498 | lang 499 | 500 | name 501 | constant.language.language_tag.turtle 502 | 503 | 504 | match 505 | (?x) 506 | (')[^'\\]*(?:\.[^'\\]*)*(') 507 | (?<lang>@(?:[a-z]{2}(?:-[a-z0-9]{2})*)?)? 508 | (?<dt>\^\^\w*:\w*|\<[^\>]+\>)? 509 | 510 | name 511 | string.quoted.single.turtle 512 | 513 | literal_triple 514 | 515 | begin 516 | (['"]{3}) 517 | beginCaptures 518 | 519 | 1 520 | 521 | name 522 | punctuation.definition.string.begin.turtle 523 | 524 | 525 | end 526 | (?x) 527 | (\1) 528 | (?<lang>@(?:[a-z]{2}(?:-[a-z0-9]{2})*)?)? 529 | (?<dt>\^\^\w*:\w*|\<[^\>]+\>)? 530 | (?=[ ]*[.;,]?) 531 | 532 | endCaptures 533 | 534 | 1 535 | 536 | name 537 | punctuation.definition.string.end.turtle 538 | 539 | dt 540 | 541 | name 542 | storage.type.datatype.turtle 543 | 544 | lang 545 | 546 | name 547 | constant.language.language_tag.turtle 548 | 549 | 550 | name 551 | string.quoted.triple.turtle 552 | 553 | sparqlClausedKeywords 554 | 555 | begin 556 | (?x)( 557 | (?# Special case because FILTER can have clauses what makes the lexer dizzy) 558 | FILTER 559 | )\s*(\((?=\s*)) 560 | beginCaptures 561 | 562 | 1 563 | 564 | name 565 | keyword.control.sparql.turtle 566 | 567 | 2 568 | 569 | name 570 | punctuation.terminator.sparqlKeyword.turtle 571 | 572 | 573 | end 574 | \s*(\)) 575 | endCaptures 576 | 577 | 1 578 | 579 | name 580 | punctuation.terminator.sparqlKeyword.turtle 581 | 582 | 583 | patterns 584 | 585 | 586 | include 587 | #sparqlVars 588 | 589 | 590 | include 591 | #sparqlFilterFns 592 | 593 | 594 | include 595 | #sparqlLangConsts 596 | 597 | 598 | 599 | sparqlFilterFns 600 | 601 | begin 602 | (?x)( 603 | (?# Special case because FILTER can have clauses what makes the lexer dizzy) 604 | FILTER| 605 | (?# Builtin callables ) 606 | STR|LANG|LANGMATCHES|DATATYPE|BOUND|IRI|URI|BNODE|RAND|ABS|CEIL|FLOOR|ROUND|CONCAT|STRLEN|UCASE|LCASE|ENCODE_FOR_URI|CONTAINS|STRSTARTS|STRENDS|STRBEFORE|STRAFTER|YEAR|MONTH|DAY|HOURS|MINUTES|SECONDS|TIMEZONE|TZ|NOW|UUID|STRUUID|MD5|SHA1|SHA256|SHA384|SHA512|COALESCE|IF|STRLANG|STRDT|sameTerm|isIRI|isURI|isBLANK|isLITERAL|isNUMERIC|COUNT|SUM|MIN|MAX|AVG|SAMPLE|GROUP_CONCAT| 607 | BOUND|COALESCE|NOT EXISTS|EXISTS|REGEX|SUBSTR|REPLACE 608 | )\s*(\((?=\s*)) 609 | beginCaptures 610 | 611 | 1 612 | 613 | name 614 | support.function.sparql.turtle 615 | 616 | 2 617 | 618 | name 619 | punctuation.terminator.sparqlFunc.turtle 620 | 621 | 622 | end 623 | \s*(\)) 624 | endCaptures 625 | 626 | 1 627 | 628 | name 629 | punctuation.terminator.sparqlFunc.turtle 630 | 631 | 632 | patterns 633 | 634 | 635 | include 636 | #sparqlVars 637 | 638 | 639 | include 640 | #sparqlFilterFns 641 | 642 | 643 | include 644 | #sparqlLangConsts 645 | 646 | 647 | 648 | sparqlKeywords 649 | 650 | match 651 | (?x)( 652 | (?# SPARQL ) 653 | SELECT|ASK|CONSTRUCT|DESCRIBE|FROM|NAMED|WHERE|GRAPH|AS| 654 | UNION|FILTER|HAVING|VALUES| 655 | OPTIONAL|SERVICE| 656 | (?# SPARUL ) 657 | SILENT|DATA| 658 | ADD|MOVE|COPY| 659 | INSERT|DELETE| 660 | LOAD|INTO| 661 | GRAPH|ALL|DEFAULT| 662 | CLEAR|CREATE|DROP| 663 | WITH|USING| 664 | (?# Solution sequence modifiers ) 665 | DISTINCT|REDUCED| 666 | ORDER|ASC|DESC|OFFSET|LIMITED|REDUCED| 667 | GROUP|BY|LIMIT 668 | ) 669 | name 670 | keyword.control.sparql.turtle 671 | 672 | sparqlLangConsts 673 | 674 | match 675 | (true|false) 676 | name 677 | constant.language.sparql.turtle 678 | 679 | sparqlVars 680 | 681 | comment 682 | Argh! 683 | match 684 | (\?\w+|\*) 685 | name 686 | constant.variable.sparql.turtle 687 | 688 | triples 689 | 690 | begin 691 | (?i)^(?!@|\#|PREFIX|BASE) 692 | beginCaptures 693 | 694 | 1 695 | 696 | name 697 | meta.spec.triples.turtle 698 | 699 | 700 | end 701 | ([.;,]?)$ 702 | endCaptures 703 | 704 | 1 705 | 706 | name 707 | punctuation.terminator.triple.turtle 708 | 709 | 710 | name 711 | meta.spec.triples.turtle 712 | patterns 713 | 714 | 715 | captures 716 | 717 | 1 718 | 719 | name 720 | punctuation.definition.comment.turtle 721 | 722 | 723 | comment 724 | Allow inline comments 725 | match 726 | (#.+$) 727 | name 728 | comment.line.number-sign.turtle 729 | 730 | 731 | comment 732 | Trying to eat up terminators before anything else (seems to work) 733 | match 734 | [.;,](?=\s|\b) 735 | name 736 | punctuation.terminator.stmt.turtle 737 | 738 | 739 | include 740 | #literal 741 | 742 | 743 | include 744 | #sparqlVars 745 | 746 | 747 | include 748 | #sparqlClausedKeywords 749 | 750 | 751 | include 752 | #sparqlKeywords 753 | 754 | 755 | include 756 | #sparqlFilterFns 757 | 758 | 759 | include 760 | #sparqlLangConsts 761 | 762 | 763 | include 764 | #blankNodePropertyList 765 | 766 | 767 | include 768 | #iri 769 | 770 | 771 | include 772 | #BlankNode 773 | 774 | 775 | include 776 | #collection 777 | 778 | 779 | match 780 | \b(a)(?=[ ]) 781 | name 782 | keyword.other.typeOf.turtle 783 | 784 | 785 | 786 | turtleDoc 787 | 788 | begin 789 | ^ 790 | end 791 | \z 792 | name 793 | meta.spec.turtleDoc.turtle 794 | patterns 795 | 796 | 797 | captures 798 | 799 | 1 800 | 801 | name 802 | punctuation.definition.comment.turtle 803 | 804 | 805 | comment 806 | Allow comment lines 807 | match 808 | ^(#).+$ 809 | name 810 | comment.line.number-sign.turtle 811 | 812 | 813 | include 814 | #directive 815 | 816 | 817 | include 818 | #sparqlClausedKeywords 819 | 820 | 821 | include 822 | #sparqlKeywords 823 | 824 | 825 | include 826 | #sparqlFilterFns 827 | 828 | 829 | include 830 | #sparqlLangConsts 831 | 832 | 833 | include 834 | #sparqlVars 835 | 836 | 837 | include 838 | #triples 839 | 840 | 841 | 842 | 843 | scopeName 844 | source.turtle 845 | uuid 846 | 3EB8C7E3-67FD-41FF-A257-6466443C6503 847 | 848 | 849 | -------------------------------------------------------------------------------- /Templates/Empty TTL file/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | command 6 | if [[ ! -f "$TM_NEW_FILE" ]]; then 7 | TM_DATE=`date +%Y-%m-%d` \ 8 | perl -pe 's/\$\{([^}]*)\}/$ENV{$1}/g' \ 9 | < index.html > "$TM_NEW_FILE" 10 | fi 11 | extension 12 | ttl 13 | name 14 | Empty TTL file 15 | scope 16 | source.ttl 17 | uuid 18 | E6F19171-F664-4B4F-92DA-3E15E6CAD35A 19 | 20 | 21 | -------------------------------------------------------------------------------- /Templates/Empty TTL file/template.ttl: -------------------------------------------------------------------------------- 1 | @prefix rdf: . 2 | @prefix rdfs: . 3 | @prefix xsd: . 4 | @prefix : . 5 | 6 | # Created: ${TM_DATE} 7 | # Author: ${TM_FULLNAME} -------------------------------------------------------------------------------- /Tests/.gitignore: -------------------------------------------------------------------------------- 1 | resource-completion* 2 | demo-files/ -------------------------------------------------------------------------------- /Themes/SemWeb Classic.tmTheme: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | author 6 | Peter Geil 7 | comment 8 | Based on Mac Classic 9 | isDisabled 10 | 11 | name 12 | SemWeb Classic 13 | scope 14 | source.turtle 15 | semanticClass 16 | theme.light.semwebclassic 17 | settings 18 | 19 | 20 | settings 21 | 22 | background 23 | #FFFFFF 24 | caret 25 | #000000 26 | foreground 27 | #000000 28 | invisibles 29 | #BFBFBF 30 | lineHighlight 31 | #00000012 32 | selection 33 | #4D97FF54 34 | 35 | 36 | 37 | name 38 | Comment 39 | scope 40 | comment 41 | settings 42 | 43 | fontStyle 44 | italic 45 | foreground 46 | #0066FF 47 | 48 | 49 | 50 | name 51 | Foldings 52 | scope 53 | deco.folding 54 | settings 55 | 56 | foreground 57 | #C5060B 58 | 59 | 60 | 61 | name 62 | Keyword 63 | scope 64 | keyword, storage 65 | settings 66 | 67 | fontStyle 68 | bold 69 | foreground 70 | #0000FF 71 | 72 | 73 | 74 | name 75 | Number 76 | scope 77 | constant.numeric 78 | settings 79 | 80 | fontStyle 81 | 82 | foreground 83 | #0000CD 84 | 85 | 86 | 87 | name 88 | User-defined constant 89 | scope 90 | constant 91 | settings 92 | 93 | fontStyle 94 | bold 95 | foreground 96 | #C5060B 97 | 98 | 99 | 100 | name 101 | Built-in constant 102 | scope 103 | constant.language 104 | settings 105 | 106 | fontStyle 107 | bold 108 | foreground 109 | #585CF6 110 | 111 | 112 | 113 | name 114 | Variable 115 | scope 116 | variable.language, variable.other 117 | settings 118 | 119 | fontStyle 120 | 121 | foreground 122 | #318495 123 | 124 | 125 | 126 | name 127 | String 128 | scope 129 | string 130 | settings 131 | 132 | fontStyle 133 | 134 | foreground 135 | #036A07 136 | 137 | 138 | 139 | name 140 | String interpolation 141 | scope 142 | constant.character.escape, string source 143 | settings 144 | 145 | fontStyle 146 | 147 | foreground 148 | #26B31A 149 | 150 | 151 | 152 | name 153 | Preprocessor line 154 | scope 155 | meta.preprocessor 156 | settings 157 | 158 | fontStyle 159 | 160 | foreground 161 | #1A921C 162 | 163 | 164 | 165 | name 166 | Preprocessor directive 167 | scope 168 | keyword.control.import 169 | settings 170 | 171 | fontStyle 172 | bold 173 | foreground 174 | #0C450D 175 | 176 | 177 | 178 | name 179 | Function name 180 | scope 181 | entity.name.function, support.function.any-method 182 | settings 183 | 184 | fontStyle 185 | bold 186 | foreground 187 | #0000A2 188 | 189 | 190 | 191 | name 192 | Type name 193 | scope 194 | entity.name.type 195 | settings 196 | 197 | fontStyle 198 | underline 199 | 200 | 201 | 202 | name 203 | Inherited class name 204 | scope 205 | entity.other.inherited-class 206 | settings 207 | 208 | fontStyle 209 | italic 210 | 211 | 212 | 213 | name 214 | Function parameter 215 | scope 216 | variable.parameter 217 | settings 218 | 219 | fontStyle 220 | italic 221 | 222 | 223 | 224 | name 225 | Function argument and result types 226 | scope 227 | storage.type.method 228 | settings 229 | 230 | fontStyle 231 | 232 | foreground 233 | #70727E 234 | 235 | 236 | 237 | name 238 | Section 239 | scope 240 | meta.section entity.name.section, declaration.section entity.name.section 241 | settings 242 | 243 | fontStyle 244 | italic 245 | 246 | 247 | 248 | name 249 | Library function 250 | scope 251 | support.function 252 | settings 253 | 254 | fontStyle 255 | bold 256 | foreground 257 | #3C4C72 258 | 259 | 260 | 261 | name 262 | Library object 263 | scope 264 | support.class, support.type 265 | settings 266 | 267 | fontStyle 268 | bold 269 | foreground 270 | #6D79DE 271 | 272 | 273 | 274 | name 275 | Library constant 276 | scope 277 | support.constant 278 | settings 279 | 280 | fontStyle 281 | bold 282 | foreground 283 | #06960E 284 | 285 | 286 | 287 | name 288 | Library variable 289 | scope 290 | support.variable 291 | settings 292 | 293 | fontStyle 294 | bold 295 | foreground 296 | #21439C 297 | 298 | 299 | 300 | name 301 | JS: Operator 302 | scope 303 | keyword.operator.js 304 | settings 305 | 306 | foreground 307 | #687687 308 | 309 | 310 | 311 | name 312 | Invalid 313 | scope 314 | invalid 315 | settings 316 | 317 | background 318 | #990000 319 | caret 320 | #FFFFFF 321 | foreground 322 | #FFFFFF 323 | selection 324 | #4D97FF 325 | 326 | 327 | 328 | name 329 | Invalid trailing whitespace 330 | scope 331 | invalid.deprecated.trailing-whitespace 332 | settings 333 | 334 | background 335 | #FFD0D0 336 | 337 | 338 | 339 | name 340 | Embedded source 341 | scope 342 | text source, string.unquoted, meta.embedded 343 | settings 344 | 345 | background 346 | #0000000D 347 | 348 | 349 | 350 | name 351 | Embedded embedded source 352 | scope 353 | text source string.unquoted, text source text source 354 | settings 355 | 356 | background 357 | #0000000F 358 | 359 | 360 | 361 | name 362 | Markup XML declaration 363 | scope 364 | meta.tag.preprocessor.xml 365 | settings 366 | 367 | fontStyle 368 | 369 | foreground 370 | #68685B 371 | 372 | 373 | 374 | name 375 | Markup DOCTYPE 376 | scope 377 | meta.tag.sgml.doctype, meta.tag.sgml.doctype entity, meta.tag.sgml.doctype string, meta.tag.preprocessor.xml, meta.tag.preprocessor.xml entity, meta.tag.preprocessor.xml string 378 | settings 379 | 380 | fontStyle 381 | 382 | foreground 383 | #888888 384 | 385 | 386 | 387 | name 388 | Markup DTD 389 | scope 390 | string.quoted.docinfo.doctype.DTD 391 | settings 392 | 393 | fontStyle 394 | italic 395 | 396 | 397 | 398 | name 399 | Markup tag 400 | scope 401 | meta.tag, declaration.tag 402 | settings 403 | 404 | fontStyle 405 | 406 | foreground 407 | #1C02FF 408 | 409 | 410 | 411 | name 412 | Markup name of tag 413 | scope 414 | entity.name.tag 415 | settings 416 | 417 | fontStyle 418 | bold 419 | 420 | 421 | 422 | name 423 | Markup tag attribute 424 | scope 425 | entity.other.attribute-name 426 | settings 427 | 428 | fontStyle 429 | italic 430 | 431 | 432 | 433 | name 434 | Markup: Heading 435 | scope 436 | markup.heading 437 | settings 438 | 439 | fontStyle 440 | bold 441 | foreground 442 | #0C07FF 443 | 444 | 445 | 446 | name 447 | Markup: Quote 448 | scope 449 | markup.quote 450 | settings 451 | 452 | fontStyle 453 | italic 454 | foreground 455 | #000000 456 | 457 | 458 | 459 | name 460 | Markup: List 461 | scope 462 | markup.list 463 | settings 464 | 465 | foreground 466 | #B90690 467 | 468 | 469 | 470 | scope 471 | meta.spec.directive 472 | settings 473 | 474 | background 475 | #ffffcc 476 | 477 | 478 | 479 | scope 480 | meta.spec.blankNodePropertyList 481 | settings 482 | 483 | background 484 | #0000008 485 | 486 | 487 | 488 | scope 489 | punctuation.terminator 490 | settings 491 | 492 | background 493 | #ffffff 494 | 495 | 496 | 497 | uuid 498 | 675B4973-6035-4CB7-A4A6-BC09C3E122F2 499 | 500 | 501 | -------------------------------------------------------------------------------- /info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | contactEmailRot13 6 | choyvp@crgretrvy.anzr 7 | contactName 8 | Peter Geil 9 | description 10 | Totally awesome bundle for Turtle – the terse RDF Triple Language. 11 | mainMenu 12 | 13 | items 14 | 15 | 5B3DDC52-4AF7-45E5-AC26-837BF81208FE 16 | 533BE8C9-42EF-48EF-A1FC-5E831DC46059 17 | 57E5DA96-6449-43DA-84FB-C3493D13FA5B 18 | EB08FE12-95D5-42DA-80DE-2B8E1D18B009 19 | 84B88EA7-7B67-4DC6-9014-76B52BF60CA7 20 | 1BAF8A19-B8BD-429C-ACCA-1BADC9345A26 21 | ------------------------------------ 22 | 14F0FEA7-EE05-4445-8C09-A5E3CF3F0C46 23 | ------------------------------------ 24 | EF6E5E32-54FD-4AE1-B35E-CC16DFE18D13 25 | ------------------------------------ 26 | C2509D61-BA70-4202-AD5A-9307266295C5 27 | 2D08ACD4-99AF-46C6-B62A-FEE1CCB5A278 28 | ------------------------------------ 29 | 2F74EEC6-5174-443B-B314-781BCA3A0E85 30 | 72E360B7-71C7-4E4C-B78A-A106FB618FF2 31 | 32 | submenus 33 | 34 | 14F0FEA7-EE05-4445-8C09-A5E3CF3F0C46 35 | 36 | items 37 | 38 | A436E557-CB60-4F4E-8EAA-BE129339E5BA 39 | ------------------------------------ 40 | 5556B1D0-1E0F-4299-B8F3-15C7C843B61D 41 | 7EECA379-154D-49A2-9863-BB8F262ADA9F 42 | 8AEC30D0-7C48-435E-A9DB-B5BB3C550905 43 | ------------------------------------ 44 | A33D62D0-B570-11E2-9E96-0800200C9A66 45 | 46 | name 47 | Insert Snippets 48 | 49 | 8AEC30D0-7C48-435E-A9DB-B5BB3C550905 50 | 51 | items 52 | 53 | D7346290-2C45-4D52-BD1B-7DE7744A404E 54 | 55 | name 56 | Prefix directives 57 | 58 | A33D62D0-B570-11E2-9E96-0800200C9A66 59 | 60 | items 61 | 62 | FC109A81-1B0F-4BB3-A756-26F0D5B98EDE 63 | ED8B6D2A-F402-4065-9A8F-5EED93826652 64 | ------------------------------------ 65 | AD2225AD-5AF2-437E-9D21-8ACB9C2598D2 66 | 893B86AF-DD6B-4283-BA11-16955B1FD7A7 67 | E2F1DED8-FDF1-4E5E-8CBD-EF5030B2498B 68 | ------------------------------------ 69 | 944CC02E-E317-4FDF-9361-4A9877A8CB4A 70 | 6E33564E-A279-4BA3-A6FE-C0712026B55B 71 | 68FF6B12-FDDB-4C56-8B92-A820A1BBD930 72 | 73 | name 74 | SPARQL 75 | 76 | 77 | 78 | name 79 | Turtle 80 | uuid 81 | A340B95F-EF97-4A2C-AFF2-2EA197837BD0 82 | 83 | 84 | --------------------------------------------------------------------------------