diff --git a/bin/linguist b/bin/linguist index e086dcea..6ac8f0a7 100755 --- a/bin/linguist +++ b/bin/linguist @@ -4,6 +4,7 @@ # usage: linguist [<--breakdown>] require 'linguist/file_blob' +require 'linguist/language' require 'linguist/repository' require 'rugged' @@ -30,7 +31,7 @@ if File.directory?(path) puts file_breakdown = repo.breakdown_by_file file_breakdown.each do |lang, files| - puts "#{lang}:" + puts "#{lang}:" files.each do |file| puts file end diff --git a/lib/linguist/blob_helper.rb b/lib/linguist/blob_helper.rb index 27c4b3dd..84aa2281 100644 --- a/lib/linguist/blob_helper.rb +++ b/lib/linguist/blob_helper.rb @@ -1,6 +1,4 @@ require 'linguist/generated' -require 'linguist/language' - require 'charlock_holmes' require 'escape_utils' require 'mime/types' diff --git a/lib/linguist/file_blob.rb b/lib/linguist/file_blob.rb index 7e7f1acd..bc475023 100644 --- a/lib/linguist/file_blob.rb +++ b/lib/linguist/file_blob.rb @@ -52,5 +52,20 @@ module Linguist def size File.size(@path) end + + # Public: Get file extension. + # + # Returns a String. + def extension + # File.extname returns nil if the filename is an extension. + extension = File.extname(name) + basename = File.basename(name) + # Checks if the filename is an extension. + if extension.empty? && basename[0] == "." + basename + else + extension + end + end end end diff --git a/lib/linguist/generated.rb b/lib/linguist/generated.rb index 761288f0..974fc7ae 100644 --- a/lib/linguist/generated.rb +++ b/lib/linguist/generated.rb @@ -54,7 +54,7 @@ module Linguist name == 'Gemfile.lock' || minified_files? || compiled_coffeescript? || - xcode_project_file? || + xcode_file? || generated_parser? || generated_net_docfile? || generated_net_designer_file? || @@ -67,14 +67,14 @@ module Linguist generated_by_zephir? end - # Internal: Is the blob an XCode project file? + # Internal: Is the blob an Xcode file? # - # Generated if the file extension is an XCode project + # Generated if the file extension is an Xcode # file extension. # # Returns true of false. - def xcode_project_file? - ['.xib', '.nib', '.storyboard', '.pbxproj', '.xcworkspacedata', '.xcuserstate'].include?(extname) + def xcode_file? + ['.nib', '.xcworkspacedata', '.xcuserstate'].include?(extname) end # Internal: Is the blob minified files? @@ -256,3 +256,4 @@ module Linguist end end end + diff --git a/lib/linguist/language.rb b/lib/linguist/language.rb index f1836721..6066b204 100644 --- a/lib/linguist/language.rb +++ b/lib/linguist/language.rb @@ -9,6 +9,8 @@ end require 'linguist/classifier' require 'linguist/heuristics' require 'linguist/samples' +require 'linguist/file_blob' +require 'linguist/blob_helper' module Linguist # Language names that are recognizable by GitHub. Defined languages @@ -109,7 +111,8 @@ module Linguist # A bit of an elegant hack. If the file is executable but extensionless, # append a "magic" extension so it can be classified with other # languages that have shebang scripts. - if File.extname(name).empty? && blob.mode && (blob.mode.to_i(8) & 05) == 05 + extension = FileBlob.new(name).extension + if extension.empty? && blob.mode && (blob.mode.to_i(8) & 05) == 05 name += ".script!" end @@ -189,7 +192,8 @@ module Linguist # # Returns all matching Languages or [] if none were found. def self.find_by_filename(filename) - basename, extname = File.basename(filename), File.extname(filename) + basename = File.basename(filename) + extname = FileBlob.new(filename).extension langs = @filename_index[basename] + @extension_index[extname] langs.compact.uniq @@ -528,6 +532,7 @@ module Linguist if extnames = extensions[name] extnames.each do |extname| if !options['extensions'].include?(extname) + warn "#{name} has a sample with extension (#{extname}) that isn't explicitly defined in languages.yml" unless extname == '.script!' options['extensions'] << extname end end diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index 4347d7be..158ff1a2 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -260,6 +260,7 @@ C: extensions: - .c - .cats + - .h - .w C#: @@ -288,6 +289,7 @@ C++: - .cc - .cxx - .H + - .h - .h++ - .hh - .hpp @@ -321,7 +323,7 @@ CLIPS: CMake: extensions: - .cmake - - .cmake.in + - .in filenames: - CMakeLists.txt @@ -380,7 +382,7 @@ Clojure: - .cljscm - .cljx - .hic - - .cljs.hl + - .hl filenames: - riemann.config @@ -444,6 +446,7 @@ Coq: type: programming extensions: - .coq + - .v Cpp-ObjDump: type: data @@ -479,6 +482,12 @@ Cuda: - .cu - .cuh +Cycript: + type: programming + lexer: JavaScript + extensions: + - .cy + Cython: type: programming group: Python @@ -533,6 +542,7 @@ Dart: Diff: extensions: - .diff + - .patch Dogescript: type: programming @@ -617,6 +627,7 @@ Erlang: color: "#0faf8d" extensions: - .erl + - .escript - .hrl F#: @@ -692,6 +703,7 @@ Forth: extensions: - .fth - .4th + - .forth Frege: type: programming @@ -800,6 +812,9 @@ Gosu: color: "#82937f" extensions: - .gs + - .gst + - .gsx + - .vark Grace: type: programming @@ -835,6 +850,7 @@ Groovy: color: "#e69f56" extensions: - .groovy + - .gradle - .grt - .gtpl - .gvy @@ -857,7 +873,6 @@ HTML: extensions: - .html - .htm - - .html.hl - .st - .xhtml @@ -877,9 +892,7 @@ HTML+ERB: - erb extensions: - .erb - - .erb.deface - - .html.erb - - .html.erb.deface + - .deface HTML+PHP: type: markup @@ -897,17 +910,14 @@ Haml: type: markup extensions: - .haml - - .haml.deface - - .html.haml.deface + - .deface Handlebars: type: markup - lexer: Text only + lexer: Handlebars extensions: - .handlebars - .hbs - - .html.handlebars - - .html.hbs Harbour: type: programming @@ -945,6 +955,7 @@ IDL: color: "#e3592c" extensions: - .pro + - .dlm INI: type: data @@ -1019,6 +1030,7 @@ JSON: searchable: false extensions: - .json + - .lock - .sublime-keymap - .sublime-mousemap - .sublime-project @@ -1147,6 +1159,9 @@ Lasso: color: "#2584c3" extensions: - .lasso + - .las + - .lasso9 + - .ldml Latte: type: markup @@ -1232,6 +1247,7 @@ Lua: extensions: - .lua - .nse + - .pd_lua - .rbxs interpreters: - lua @@ -1345,7 +1361,7 @@ MiniD: # Legacy Mirah: type: programming lexer: Ruby - search_term: ruby + search_term: mirah color: "#c7a938" extensions: - .druby @@ -1377,6 +1393,7 @@ Myghty: NSIS: extensions: - .nsi + - .nsh Nemerle: type: programming @@ -1441,6 +1458,7 @@ OCaml: color: "#3be133" extensions: - .ml + - .eliom - .eliomi - .ml4 - .mli @@ -1461,6 +1479,7 @@ Objective-C: - objc extensions: - .m + - .h Objective-C++: type: programming @@ -1508,6 +1527,7 @@ OpenEdge ABL: - abl extensions: - .p + - .cls Org: type: prose @@ -1546,6 +1566,7 @@ PHP: - .php - .aw - .ctp + - .module - .php3 - .php4 - .php5 @@ -1594,6 +1615,7 @@ Pascal: extensions: - .pas - .dfm + - .dpr - .lpr Perl: @@ -1604,6 +1626,7 @@ Perl: - .pl - .PL - .cgi + - .fcgi - .perl - .ph - .plx @@ -1819,6 +1842,7 @@ Racket: - .rkt - .rktd - .rktl + - .scrbl Ragel in Ruby Host: type: programming @@ -1888,7 +1912,10 @@ Ruby: - .god - .irbrc - .mspec + - .pluginspec - .podspec + - .rabl + - .rake - .rbuild - .rbw - .rbx @@ -1962,6 +1989,7 @@ Sass: group: CSS extensions: - .sass + - .scss Scala: type: programming @@ -1969,6 +1997,7 @@ Scala: color: "#7dd3b0" extensions: - .scala + - .sbt - .sc Scaml: @@ -1984,6 +2013,7 @@ Scheme: - .scm - .sld - .sls + - .sps - .ss interpreters: - guile @@ -1995,6 +2025,8 @@ Scilab: type: programming extensions: - .sci + - .sce + - .tst Self: type: programming @@ -2014,8 +2046,10 @@ Shell: - zsh extensions: - .sh + - .bash - .bats - .tmux + - .zsh interpreters: - bash - sh @@ -2082,6 +2116,7 @@ Standard ML: extensions: - .ML - .fun + - .sig - .sml Stata: @@ -2282,6 +2317,7 @@ Visual Basic: extensions: - .vb - .bas + - .cls - .frm - .frx - .vba @@ -2310,6 +2346,7 @@ XML: - wsdl extensions: - .xml + - .ant - .axml - .ccxml - .clixml @@ -2323,6 +2360,7 @@ XML: - .fsproj - .glade - .grxml + - .ivy - .jelly - .kml - .launch diff --git a/lib/linguist/samples.json b/lib/linguist/samples.json index 8ea2394a..d1b10626 100644 --- a/lib/linguist/samples.json +++ b/lib/linguist/samples.json @@ -92,7 +92,8 @@ ".cljs", ".cljscm", ".cljx", - ".hic" + ".hic", + ".hl" ], "CoffeeScript": [ ".coffee" @@ -118,6 +119,9 @@ ".cu", ".cuh" ], + "Cycript": [ + ".cy" + ], "DM": [ ".dm" ], @@ -209,7 +213,12 @@ ".html", ".st" ], + "HTML+ERB": [ + ".deface", + ".erb" + ], "Haml": [ + ".deface", ".haml" ], "Handlebars": [ @@ -740,6 +749,9 @@ "Nginx": [ "nginx.conf" ], + "PHP": [ + ".php" + ], "Perl": [ "ack" ], @@ -782,6 +794,9 @@ ".gvimrc", ".vimrc" ], + "XML": [ + ".cproject" + ], "YAML": [ ".gemrc" ], @@ -791,8 +806,8 @@ "exception.zep.php" ] }, - "tokens_total": 629226, - "languages_total": 867, + "tokens_total": 632405, + "languages_total": 874, "tokens": { "ABAP": { "*/**": 1, @@ -15172,77 +15187,247 @@ "container": 3 }, "Clojure": { - "(": 83, - "defn": 4, + "(": 258, + "defn": 14, "prime": 2, - "[": 41, + "[": 67, "n": 9, - "]": 41, - "not": 3, - "-": 14, - "any": 1, - "zero": 1, - "map": 2, - "#": 1, + "]": 67, + "not": 9, + "-": 70, + "any": 3, + "zero": 2, + "map": 3, + "#": 14, "rem": 2, - "%": 1, - ")": 84, + "%": 6, + ")": 259, "range": 3, - ";": 8, + ";": 353, "while": 3, "stops": 1, - "at": 1, - "the": 1, + "at": 2, + "the": 5, "first": 2, "collection": 1, "element": 1, "that": 1, "evaluates": 1, - "to": 1, - "false": 2, + "to": 2, + "false": 6, "like": 1, "take": 1, - "for": 2, - "x": 6, - "html": 1, - "head": 1, - "meta": 1, - "{": 8, - "charset": 1, - "}": 8, - "link": 1, - "rel": 1, - "href": 1, + "for": 4, + "x": 8, + "html": 2, + "head": 2, + "meta": 3, + "{": 17, + "charset": 2, + "}": 17, + "link": 2, + "rel": 2, + "href": 6, "script": 1, "src": 1, - "body": 1, + "body": 2, "div.nav": 1, - "p": 1, - "into": 2, + "p": 4, + "Copyright": 1, + "c": 1, + "Alan": 1, + "Dipert": 1, + "and": 8, + "Micha": 1, + "Niskin.": 1, + "All": 1, + "rights": 1, + "reserved.": 1, + "The": 1, + "use": 3, + "distribution": 1, + "terms": 2, + "this": 6, + "software": 2, + "are": 2, + "covered": 1, + "by": 4, + "Eclipse": 1, + "Public": 1, + "License": 1, + "http": 2, + "//opensource.org/licenses/eclipse": 1, + "php": 1, + "which": 2, + "can": 1, + "be": 2, + "found": 1, + "in": 4, + "file": 1, + "epl": 1, + "v10.html": 1, + "root": 1, + "of": 2, + "distribution.": 1, + "By": 1, + "using": 1, + "fashion": 1, + "you": 1, + "agreeing": 1, + "bound": 1, + "license.": 1, + "You": 1, + "must": 1, + "remove": 3, + "notice": 1, + "or": 2, + "other": 1, + "from": 1, + "software.": 1, + "page": 2, + "refer": 4, + "clojure": 1, + "exclude": 1, + "nth": 2, + "require": 2, + "tailrecursion.hoplon.reload": 1, + "reload": 2, + "all": 5, + "tailrecursion.hoplon.util": 1, + "name": 1, + "pluralize": 2, + "tailrecursion.hoplon.storage": 1, + "atom": 1, + "local": 3, + "storage": 2, + "utility": 1, + "functions": 2, + "declare": 1, + "route": 11, + "state": 15, + "editing": 13, + "def": 4, + "mapvi": 2, + "comp": 1, + "vec": 2, + "indexed": 1, + "dissocv": 2, + "v": 15, + "i": 20, + "let": 3, + "z": 4, + "dec": 1, + "count": 5, + "cond": 2, + "neg": 1, + "pop": 1, + "pos": 1, + "into": 3, + "subvec": 2, + "inc": 2, + "decorate": 2, + "todo": 10, + "done": 12, + "completed": 12, + "text": 14, + "assoc": 4, + "visible": 2, + "empty": 8, + "persisted": 1, + "cell": 12, + "AKA": 1, + "stem": 1, + "store": 1, + "cells": 2, + "defc": 6, + "loaded": 1, + "nil": 3, + "formula": 1, + "computed": 1, + "filter": 2, + "active": 5, + "plural": 1, + "item": 1, + "todos": 2, + "list": 1, + "transition": 1, + "t": 5, + "destroy": 3, + "swap": 6, + "clear": 2, + "&": 1, + "_": 4, + "new": 5, + "when": 3, + "conj": 1, + "mapv": 1, + "fn": 3, + "reset": 1, + "if": 3, + "lang": 1, + "equiv": 1, + "content": 1, + "title": 1, + "noscript": 1, + "div": 3, + "id": 20, + "section": 2, + "header": 1, + "h1": 1, + "form": 2, + "on": 11, + "submit": 2, + "do": 15, + "val": 4, + "value": 3, + "input": 4, + "type": 8, + "autofocus": 1, + "true": 5, + "placeholder": 1, + "blur": 2, + "toggle": 4, + "attr": 2, + "checked": 2, + "click": 4, + "label": 2, + "ul": 2, + "loop": 2, + "tpl": 1, + "reverse": 1, + "bind": 1, + "ids": 1, + "done#": 3, + "edit#": 3, + "bindings": 1, + "edit": 3, + "show": 2, + "li": 4, + "class": 8, + "dblclick": 1, + "@i": 6, + "button": 2, + "focus": 1, + "@edit": 2, + "change": 1, + "footer": 2, + "span": 2, + "strong": 1, + "a": 7, + "selected": 3, "array": 3, "aseq": 8, - "nil": 1, - "type": 2, - "let": 1, - "count": 3, - "a": 3, "make": 1, - "loop": 1, "seq": 1, - "i": 4, - "if": 1, "<": 1, - "do": 1, "aset": 1, "recur": 1, "next": 1, - "inc": 1, "defprotocol": 1, "ISound": 4, "sound": 5, "deftype": 2, "Cat": 1, - "_": 3, "Dog": 1, "extend": 1, "default": 1, @@ -15253,7 +15438,6 @@ "clj": 1, "ns": 2, "c2.svg": 2, - "use": 2, "c2.core": 2, "only": 4, "unify": 2, @@ -15267,39 +15451,30 @@ "cos": 2, "mean": 2, "cljs": 3, - "require": 1, "c2.dom": 1, "as": 1, "dom": 1, "Stub": 1, "float": 2, - "fn": 2, - "which": 1, "does": 1, "exist": 1, - "on": 1, "runtime": 1, - "def": 1, "identity": 1, "xy": 1, "coordinates": 7, - "cond": 1, - "and": 1, "vector": 1, "y": 1, "deftest": 1, "function": 1, "tests": 1, "is": 7, - "true": 2, "contains": 1, "foo": 6, "bar": 4, "select": 1, "keys": 2, "baz": 4, - "vals": 1, - "filter": 1 + "vals": 1 }, "CoffeeScript": { "CoffeeScript": 1, @@ -18273,6 +18448,122 @@ "cudaDeviceReset": 1, "return": 1 }, + "Cycript": { + "(": 12, + "function": 2, + "utils": 2, + ")": 12, + "{": 8, + "//": 4, + "Load": 1, + "C": 2, + "functions": 3, + "declared": 1, + "in": 2, + "utils.loadFuncs": 1, + "var": 6, + "shouldLoadCFuncs": 2, + "true": 2, + ";": 21, + "Expose": 2, + "the": 1, + "to": 4, + "cycript": 2, + "s": 2, + "global": 1, + "scope": 1, + "shouldExposeConsts": 2, + "defined": 1, + "here": 1, + "t": 1, + "be": 2, + "found": 2, + "with": 1, + "dlsym": 1, + "Failed": 1, + "load": 1, + "mach_vm_address_t": 1, + "string": 4, + "@encode": 2, + "infinite": 1, + "*": 1, + "length": 1, + "[": 8, + "object": 1, + "Struct": 1, + "]": 8, + "%": 8, + "@": 3, + "<%@:>": 1, + "0x": 1, + "+": 3, + "-": 2, + "printf": 1, + ".3s": 1, + "d": 2, + "c": 5, + "float": 1, + "f": 1, + "n": 1, + "foo": 2, + "barrrr": 1, + "Args": 1, + "needs": 1, + "an": 1, + "array": 1, + "number": 1, + "Function": 1, + "not": 1, + "foobar": 2, + "strdup": 2, + "pipe": 1, + "write": 1, + "close": 2, + "int": 1, + "a": 1, + "short": 1, + "b": 1, + "char": 1, + "uint64_t": 1, + "double": 1, + "e": 1, + "struct": 1, + "}": 9, + "return": 1, + "new": 1, + "Type": 1, + "typeStr": 1, + "Various": 1, + "constants": 1, + "utils.constants": 2, + "VM_PROT_NONE": 1, + "VM_PROT_READ": 1, + "VM_PROT_WRITE": 1, + "VM_PROT_EXECUTE": 1, + "VM_PROT_NO_CHANGE": 1, + "VM_PROT_COPY": 1, + "VM_PROT_WANTS_COPY": 1, + "VM_PROT_IS_MASK": 1, + "c.VM_PROT_DEFAULT": 1, + "c.VM_PROT_READ": 2, + "|": 3, + "c.VM_PROT_WRITE": 2, + "c.VM_PROT_ALL": 1, + "c.VM_PROT_EXECUTE": 1, + "if": 3, + "for": 2, + "k": 3, + "Cycript.all": 2, + "shouldExposeFuncs": 1, + "i": 4, + "<": 1, + "funcsToExpose.length": 1, + "name": 3, + "funcsToExpose": 1, + "utils.loadfuncs": 1, + "shouldExposeCFuncs": 1, + "exports": 1 + }, "DM": { "#define": 4, "PI": 6, @@ -25999,8 +26290,139 @@ "with": 1, "Doxygen": 1 }, + "HTML+ERB": { + "<%>": 12, + "if": 3, + "Spree": 4, + "Config": 4, + "enable_fishbowl": 1, + "
": 23, + "class=": 24, + "id=": 1, + "
": 1, + "": 1, + "align=": 1, + "<%=>": 12, + "t": 4, + "fishbowl_settings": 1, + "": 1, + "fishbowl_options": 1, + "each": 1, + "do": 2, + "key": 5, + "label_tag": 2, + "to_s": 2, + "gsub": 1, + "fishbowl_": 1, + "to_sym": 1, + "tag": 2, + "br": 2, + "text_field_tag": 1, + "preferences": 4, + "size": 1, + "class": 2, + "}": 3, + ")": 4, + "%": 2, + "
": 23, + "end": 5, + "hidden_field_tag": 1, + "fishbowl_always_fetch_current_inventory": 3, + "0": 1, + "check_box_tag": 1, + "1": 1, + "always_fetch_current_inventory": 1, + "location_groups": 2, + "empty": 1, + "fishbowl_location_group": 3, + "location_group": 1, + "select": 1, + "selected": 1, + "[": 2, + "]": 2, + "{": 1, + "": 1, + "": 1, + "provide": 1, + "title": 1, + "header": 2, + "present": 1, + "users": 3, + "user_presenter": 1, + "

": 1, + "

": 1, + "will_paginate": 2, + "Name": 1, + "Email": 1, + "Chords": 1, + "Keys": 1, + "Tunings": 1, + "Credits": 1, + "Prem": 1, + "Since": 1, + "No": 1, + "Users": 1, + "else": 1, + "render": 1 + }, "Haml": { - "%": 1, + "/": 1, + "replace": 1, + ".pull": 1, + "-": 16, + "right": 1, + ".btn": 2, + "group": 2, + "link_to": 4, + "page.url": 1, + "target": 1, + "title": 5, + "t": 5, + "(": 10, + ")": 10, + "class": 4, + "do": 4, + "%": 7, + "i.icon": 5, + "picture.row": 1, + "black": 1, + "refinery.edit_admin_page_path": 1, + "page.nested_url": 2, + "switch_locale": 1, + "page.translations.first.locale": 1, + "unless": 1, + "page.translated_to_default_locale": 1, + "scope": 4, + "edit.row": 1, + "blue": 1, + "if": 1, + "page.deletable": 1, + "refinery.admin_page_path": 1, + "methode": 1, + "delete": 1, + "data": 1, + "{": 1, + "confirm": 1, + "page_title_with_translations": 1, + "page": 1, + "}": 1, + "trash.row": 1, + "red": 1, + "else": 1, + "button.btn.btn": 1, + "xs.btn": 1, + "default.disabled": 1, + "trash": 1, + "refinery.new_admin_page_path": 1, + "parent_id": 1, + "page.id": 1, + "plus.row": 1, + "green": 1, "p": 1, "Hello": 1, "World": 1 @@ -49935,7 +50357,7 @@ }, "PHP": { "<": 11, - "php": 12, + "php": 14, "namespace": 28, "Symfony": 24, "Component": 24, @@ -50659,6 +51081,19 @@ "base_url": 1, "php_filter_info": 1, "filters": 2, + "SHEBANG#!php": 4, + "": 1, + "aMenuLinks": 1, + "Array": 13, + "Blog": 1, + "SITE_DIR": 4, + "Photos": 1, + "photo": 1, + "About": 1, + "me": 1, + "about": 1, + "Contact": 1, + "contacts": 1, "Field": 9, "FormField": 3, "ArrayAccess": 1, @@ -50953,7 +51388,6 @@ "isUnique": 1, "is_bool": 1, "sql": 1, - "SHEBANG#!php": 3, "echo": 2, "Yii": 3, "console": 3, @@ -67048,9 +67482,9 @@ "return": 1 }, "XML": { - "": 11, - "version=": 17, - "encoding=": 7, + "": 12, + "version=": 21, + "encoding=": 8, "": 7, "ToolsVersion=": 6, "DefaultTargets=": 5, @@ -67127,6 +67561,94 @@ "": 10, "": 5, "": 7, + "standalone=": 1, + "": 1, + "4": 1, + "0": 2, + "": 1, + "storage_type_id=": 1, + "": 14, + "moduleId=": 14, + "": 2, + "id=": 141, + "buildSystemId=": 2, + "name=": 270, + "": 2, + "": 2, + "": 12, + "point=": 12, + "": 2, + "": 7, + "": 2, + "artifactName=": 2, + "buildArtefactType=": 2, + "buildProperties=": 2, + "cleanCommand=": 2, + "description=": 4, + "cdt": 2, + "managedbuild": 2, + "config": 2, + "gnu": 2, + "exe": 2, + "debug": 1, + "1803931088": 1, + "parent=": 2, + "": 2, + "resourcePath=": 2, + "": 2, + "superClass=": 42, + "": 2, + "": 2, + "buildPath=": 2, + "keepEnvironmentInBuildfile=": 2, + "managedBuildOn=": 2, + "": 12, + "": 4, + "": 8, + "": 8, + "defaultValue=": 2, + "": 4, + "kind=": 6, + "paths=": 4, + "": 2, + "": 2, + "": 2, + "": 2, + "": 2, + "flags=": 2, + "": 2, + "": 2, + "": 2, + "release": 1, + "32754498": 1, + "": 2, + "projectType=": 1, + "": 5, + "enabled=": 125, + "problemReportingEnabled=": 5, + "selectedProfileId=": 5, + "": 40, + "": 40, + "": 40, + "filePath=": 40, + "": 80, + "": 40, + "": 40, + "": 40, + "arguments=": 40, + "command=": 40, + "useDefault=": 40, + "": 40, + "": 40, + "": 4, + "instanceId=": 4, + "": 4, + "": 1, "": 2, "": 2, "cfa7a11": 1, @@ -67174,8 +67696,6 @@ "FSharp": 1, "": 1, "": 1, - "": 1, - "name=": 227, "xmlns": 2, "ea=": 2, "": 4, @@ -67230,14 +67750,12 @@ "application": 2, "": 1, "": 1, - "value=": 1, "": 1, "": 1, "": 1, "": 1, "": 2, "visibility=": 2, - "description=": 2, "": 1, "": 1, "": 4, @@ -69660,7 +70178,7 @@ "CSS": 43867, "Ceylon": 50, "Cirru": 244, - "Clojure": 510, + "Clojure": 1899, "CoffeeScript": 2951, "Common Lisp": 2186, "Component Pascal": 825, @@ -69668,6 +70186,7 @@ "Creole": 134, "Crystal": 1506, "Cuda": 290, + "Cycript": 251, "DM": 169, "Dart": 74, "Diff": 16, @@ -69692,7 +70211,8 @@ "Groovy": 93, "Groovy Server Pages": 91, "HTML": 413, - "Haml": 4, + "HTML+ERB": 213, + "Haml": 121, "Handlebars": 69, "Haskell": 302, "Hy": 155, @@ -69756,7 +70276,7 @@ "Ox": 1006, "Oxygene": 157, "PAWN": 3263, - "PHP": 20724, + "PHP": 20754, "Pan": 130, "Parrot Assembly": 6, "Parrot Internal Representation": 5, @@ -69822,7 +70342,7 @@ "Visual Basic": 581, "Volt": 388, "XC": 24, - "XML": 7057, + "XML": 8236, "XProc": 22, "XQuery": 801, "XSLT": 44, @@ -69860,7 +70380,7 @@ "CSS": 2, "Ceylon": 1, "Cirru": 9, - "Clojure": 7, + "Clojure": 8, "CoffeeScript": 9, "Common Lisp": 3, "Component Pascal": 2, @@ -69868,6 +70388,7 @@ "Creole": 1, "Crystal": 3, "Cuda": 2, + "Cycript": 1, "DM": 1, "Dart": 1, "Diff": 1, @@ -69892,7 +70413,8 @@ "Groovy": 5, "Groovy Server Pages": 4, "HTML": 2, - "Haml": 1, + "HTML+ERB": 2, + "Haml": 2, "Handlebars": 2, "Haskell": 3, "Hy": 2, @@ -69956,7 +70478,7 @@ "Ox": 3, "Oxygene": 1, "PAWN": 1, - "PHP": 9, + "PHP": 10, "Pan": 1, "Parrot Assembly": 1, "Parrot Internal Representation": 1, @@ -70022,7 +70544,7 @@ "Visual Basic": 3, "Volt": 1, "XC": 1, - "XML": 13, + "XML": 14, "XProc": 1, "XQuery": 1, "XSLT": 1, @@ -70035,5 +70557,5 @@ "fish": 3, "wisp": 1 }, - "md5": "cedc5d3fde7e7b87467bdf820d674b95" + "md5": "87af2c0165a9c7fcb5f88e73d26b3c20" } \ No newline at end of file diff --git a/lib/linguist/vendor.yml b/lib/linguist/vendor.yml index c497960c..78e3d6a2 100644 --- a/lib/linguist/vendor.yml +++ b/lib/linguist/vendor.yml @@ -43,6 +43,10 @@ # Normalize.css - normalize.css +# Animate.css +- animate.css +- animate.min.css + # Vendored dependencies - thirdparty/ - vendors?/ @@ -112,6 +116,10 @@ - (^|/)modernizr\-\d\.\d+(\.\d+)?(\.min)?\.js$ - (^|/)modernizr\.custom\.\d+\.js$ +# Knockout +- (^|/)knockout-(\d+\.){3}(debug\.)?js$ +- knockout-min.js + ## Python ## # django diff --git a/lib/linguist/version.rb b/lib/linguist/version.rb index 89151b75..05d68a15 100644 --- a/lib/linguist/version.rb +++ b/lib/linguist/version.rb @@ -1,3 +1,3 @@ module Linguist - VERSION = "3.0.3" + VERSION = "3.1.1" end diff --git a/samples/Clojure/index.cljs.hl b/samples/Clojure/index.cljs.hl new file mode 100644 index 00000000..043df92b --- /dev/null +++ b/samples/Clojure/index.cljs.hl @@ -0,0 +1,146 @@ +;; Copyright (c) Alan Dipert and Micha Niskin. All rights reserved. +;; The use and distribution terms for this software are covered by the +;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +;; which can be found in the file epl-v10.html at the root of this distribution. +;; By using this software in any fashion, you are agreeing to be bound by +;; the terms of this license. +;; You must not remove this notice, or any other, from this software. + +(page "index.html" + (:refer-clojure :exclude [nth]) + (:require + [tailrecursion.hoplon.reload :refer [reload-all]] + [tailrecursion.hoplon.util :refer [nth name pluralize]] + [tailrecursion.hoplon.storage-atom :refer [local-storage]])) + +;; utility functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(declare route state editing) + +(reload-all) + +(def mapvi (comp vec map-indexed)) + +(defn dissocv [v i] + (let [z (- (dec (count v)) i)] + (cond (neg? z) v + (zero? z) (pop v) + (pos? z) (into (subvec v 0 i) (subvec v (inc i)))))) + +(defn decorate [todo route editing i] + (let [{done? :completed text :text} todo] + (-> todo (assoc :editing (= editing i) + :visible (and (not (empty? text)) + (or (= "#/" route) + (and (= "#/active" route) (not done?)) + (and (= "#/completed" route) done?))))))) + +;; persisted state cell (AKA: stem cell) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(def state (-> (cell []) (local-storage ::store))) + +;; local state cells ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defc loaded? false) +(defc editing nil) +(def route (route-cell "#/")) + +;; formula cells (computed state) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defc= completed (filter :completed state)) +(defc= active (remove :completed state)) +(defc= plural-item (pluralize "item" (count active))) +(defc= todos (mapvi #(list %1 (decorate %2 route editing %1)) state)) + +;; state transition functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn todo [t] {:completed false :text t}) +(defn destroy! [i] (swap! state dissocv i)) +(defn done! [i v] (swap! state assoc-in [i :completed] v)) +(defn clear-done! [& _] (swap! state #(vec (remove :completed %)))) +(defn new! [t] (when (not (empty? t)) (swap! state conj (todo t)))) +(defn all-done! [v] (swap! state #(mapv (fn [x] (assoc x :completed v)) %))) +(defn editing! [i v] (reset! editing (if v i nil))) +(defn text! [i v] (if (empty? v) (destroy! i) (swap! state assoc-in [i :text] v))) + +;; page ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(html :lang "en" + (head + (meta :charset "utf-8") + (meta :http-equiv "X-UA-Compatible" :content "IE=edge,chrome=1") + (link :rel "stylesheet" :href "base.css") + (title "Hoplon • TodoMVC")) + (body + (noscript + (div :id "noscript" + (p "JavaScript is required to view this page."))) + (div + (section :id "todoapp" + (header :id "header" + (h1 "todos") + (form :on-submit #(do (new! (val-id :new-todo)) + (do! (by-id :new-todo) :value "")) + (input + :id "new-todo" + :type "text" + :autofocus true + :placeholder "What needs to be done?" + :on-blur #(do! (by-id :new-todo) :value "")))) + (section + :id "main" + :do-toggle (cell= (not (and (empty? active) (empty? completed)))) + (input + :id "toggle-all" + :type "checkbox" + :do-attr (cell= {:checked (empty? active)}) + :on-click #(all-done! (val-id :toggle-all))) + (label :for "toggle-all" + "Mark all as complete") + (ul :id "todo-list" + (loop-tpl + :reverse true + :bind-ids [done# edit#] + :bindings [[i {edit? :editing done? :completed todo-text :text show? :visible}] todos] + (li + :do-class (cell= {:completed done? :editing edit?}) + :do-toggle show? + (div :class "view" :on-dblclick #(editing! @i true) + (input + :id done# + :type "checkbox" + :class "toggle" + :do-attr (cell= {:checked done?}) + :on-click #(done! @i (val-id done#))) + (label (text "~{todo-text}")) + (button + :type "submit" + :class "destroy" + :on-click #(destroy! @i))) + (form :on-submit #(editing! @i false) + (input + :id edit# + :type "text" + :class "edit" + :do-value todo-text + :do-focus edit? + :on-blur #(when @edit? (editing! @i false)) + :on-change #(when @edit? (text! @i (val-id edit#))))))))) + (footer + :id "footer" + :do-toggle (cell= (not (and (empty? active) (empty? completed)))) + (span :id "todo-count" + (strong (text "~(count active) ")) + (span (text "~{plural-item} left"))) + (ul :id "filters" + (li (a :href "#/" :do-class (cell= {:selected (= "#/" route)}) "All")) + (li (a :href "#/active" :do-class (cell= {:selected (= "#/active" route)}) "Active")) + (li (a :href "#/completed" :do-class (cell= {:selected (= "#/completed" route)}) "Completed"))) + (button + :type "submit" + :id "clear-completed" + :on-click #(clear-done!) + (text "Clear completed (~(count completed))")))) + (footer :id "info" + (p "Double-click to edit a todo") + (p "Part of " (a :href "http://github.com/tailrecursion/hoplon-demos/" "hoplon-demos")))))) diff --git a/samples/Cycript/utils.cy b/samples/Cycript/utils.cy new file mode 100644 index 00000000..72e677b7 --- /dev/null +++ b/samples/Cycript/utils.cy @@ -0,0 +1,580 @@ +(function(utils) { + // Load C functions declared in utils.loadFuncs + var shouldLoadCFuncs = true; + // Expose the C functions to cycript's global scope + var shouldExposeCFuncs = true; + // Expose C constants to cycript's global scope + var shouldExposeConsts = true; + // Expose functions defined here to cycript's global scope + var shouldExposeFuncs = true; + // Which functions to expose + var funcsToExpose = ["exec", "include", "sizeof", "logify", "apply", "str2voidPtr", "voidPtr2str", "double2voidPtr", "voidPtr2double", "isMemoryReadable", "isObject", "makeStruct"]; + + // C functions that utils.loadFuncs loads + var CFuncsDeclarations = [ + // + "void *calloc(size_t num, size_t size)", + // + "char *strcpy(char *restrict dst, const char *restrict src)", + "char *strdup(const char *s1)", + "void* memset(void* dest, int ch, size_t count)", + // + "FILE *fopen(const char *, const char *)", + "int fclose(FILE *)", + "size_t fread(void *restrict, size_t, size_t, FILE *restrict)", + "size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict)", + // + "mach_port_t mach_task_self()", + "kern_return_t task_for_pid(mach_port_name_t target_tport, int pid, mach_port_name_t *tn)", + "kern_return_t mach_vm_protect(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection)", + "kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt)", + "kern_return_t mach_vm_read(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_offset_t *data, mach_msg_type_number_t *dataCnt)", + ]; + + /* + Replacement for eval that can handle @encode etc. + + Usage: + cy# utils.exec("@encode(void *(int, char))") + @encode(void*(int,char)) + */ + utils.exec = function(str) { + var mkdir = @encode(int (const char *, int))(dlsym(RTLD_DEFAULT, "mkdir")); + var tempnam = @encode(char *(const char *, const char *))(dlsym(RTLD_DEFAULT, "tempnam")); + var fopen = @encode(void *(const char *, const char *))(dlsym(RTLD_DEFAULT, "fopen")); + var fclose = @encode(int (void *))(dlsym(RTLD_DEFAULT, "fclose")); + var fwrite = @encode(int (const char *, int, int, void *))(dlsym(RTLD_DEFAULT, "fwrite")); + var symlink = @encode(int (const char *, const char *))(dlsym(RTLD_DEFAULT, "symlink")); + var unlink = @encode(int (const char *))(dlsym(RTLD_DEFAULT, "unlink")); + var getenv = @encode(const char *(const char *))(dlsym(RTLD_DEFAULT, "getenv")); + var setenv = @encode(int (const char *, const char *, int))(dlsym(RTLD_DEFAULT, "setenv")); + + var libdir = "/usr/lib/cycript0.9"; + var dir = libdir + "/tmp"; + + mkdir(dir, 0777); + + // This is needed because tempnam seems to ignore the first argument on i386 + var old_tmpdir = getenv("TMPDIR"); + setenv("TMPDIR", dir, 1); + + // No freeing :( + var f = tempnam(dir, "exec-"); + setenv("TMPDIR", old_tmpdir, 1); + if(!f) { + return false; + } + + symlink(f, f + ".cy"); + + str = "exports.result = " + str; + + var handle = fopen(f, "w"); + fwrite(str, str.length, 1, handle); + fclose(handle); + + var r; + var except = null; + try { + r = require(f.replace(libdir + "/", "")); + } catch(e) { + except = e; + } + + unlink(f + ".cy"); + unlink(f); + + if(except !== null) { + throw except; + } + + return r.result; + }; + + /* + Applies known typedefs + Used in utils.include and utils.makeStruct + + Usage: + cy# utils.applyTypedefs("mach_vm_address_t") + "uint64_t" + */ + utils.applyTypedefs = function(str) { + var typedefs = { + "struct": "", + "restrict": "", + "FILE": "void", + "size_t": "uint64_t", + "uintptr_t": "unsigned long", + "kern_return_t": "int", + "mach_port_t": "unsigned int", + "mach_port_name_t": "unsigned int", + "vm_offset_t": "unsigned long", + "vm_size_t": "unsigned long", + "mach_vm_address_t": "uint64_t", + "mach_vm_offset_t": "uint64_t", + "mach_vm_size_t": "uint64_t", + "vm_map_offset_t": "uint64_t", + "vm_map_address_t": "uint64_t", + "vm_map_size_t": "uint64_t", + "mach_port_context_t": "uint64_t", + "vm_map_t": "unsigned int", + "boolean_t": "unsigned int", + "vm_prot_t": "int", + "mach_msg_type_number_t": "unsigned int", + "cpu_type_t": "int", + "cpu_subtype_t": "int", + "cpu_threadtype_t": "int", + }; + + for(var k in typedefs) { + str = str.replace(new RegExp("(\\s|\\*|,|\\(|^)" + k + "(\\s|\\*|,|\\)|$)", "g"), "$1" + typedefs[k] + "$2"); + } + + return str; + }; + + /* + Parses a C function declaration and returns the function name and cycript type + If load is true, tries to load it into cycript using utils.exec + + Usage: + cy# var str = "void *calloc(size_t num, size_t size)"; + "void *calloc(size_t num, size_t size)" + cy# utils.include(str) + ["calloc","@encode(void *(uint64_t num, uint64_t size))(140735674376857)"] + cy# var ret = utils.include(str, true) + ["calloc",0x7fff93e0e299] + cy# ret[1].type + @encode(void*(unsigned long long int,unsigned long long int)) + cy# ret[1](100, 1) + 0x100444100 + */ + utils.include = function(str, load) { + var re = /^\s*([^(]*(?:\s+|\*))(\w*)\s*\(([^)]*)\)\s*;?\s*$/; + var match = re.exec(str); + if(!match) { + return -1; + } + var rType = utils.applyTypedefs(match[1]); + var name = match[2]; + var args = match[3]; + + var argsRe = /([^,]+)(?:,|$)/g; + var argsTypes = []; + while((match = argsRe.exec(args)) !== null) { + var type = utils.applyTypedefs(match[1]); + argsTypes.push(type); + } + + var encodeString = "@encode("; + encodeString += rType + "("; + encodeString += argsTypes.join(", ") + "))"; + + var fun = dlsym(RTLD_DEFAULT, name); + if(fun !== null) { + encodeString += "(" + fun + ")"; + if(load) { + return [name, utils.exec(encodeString)]; + } + } else if(load) { + throw "Function couldn't be found with dlsym!"; + } + + return [name, encodeString]; + }; + + /* + Loads the function declaration in the defs array using utils.exec and exposes to cycript's global scope + Is automatically called if shouldLoadCFuncs is true + */ + utils.funcs = {}; + utils.loadfuncs = function(expose) { + for(var i = 0; i < CFuncsDeclarations.length; i++) { + try { + var o = utils.include(CFuncsDeclarations[i], true); + utils.funcs[o[0]] = o[1]; + if(expose) { + Cycript.all[o[0]] = o[1]; + } + } catch(e) { + system.print("Failed to load function: " + i); + try { + system.print(utils.include(CFuncsDeclarations[i])); + } catch(e2) { + + } + } + } + }; + + /* + Calculates the size of a type like the C operator sizeof + + Usage: + cy# utils.sizeof(int) + 4 + cy# utils.sizeof(@encode(void *)) + 8 + cy# utils.sizeof("mach_vm_address_t") + 8 + */ + utils.sizeof = function(type) { + if(typeof type === "string") { + type = utils.applyTypedefs(type); + type = utils.exec("@encode(" + type + ")"); + } + + // (const) char * has "infinite" preceision + if(type.toString().slice(-1) === "*") { + return utils.sizeof(@encode(void *)); + } + + // float and double + if(type.toString() === @encode(float).toString()) { + return 4; + } else if (type.toString() === @encode(double).toString()) { + return 8; + } + + var typeInstance = type(0); + + if(typeInstance instanceof Object) { + // Arrays + if("length" in typeInstance) { + return typeInstance.length * utils.sizeof(typeInstance.type); + } + + // Structs + if(typeInstance.toString() === "[object Struct]") { + var typeStr = type.toString(); + var arrayTypeStr = "[2" + typeStr + "]"; + var arrayType = new Type(arrayTypeStr); + + var arrayInstance = new arrayType; + + return @encode(void *)(&(arrayInstance[1])) - @encode(void *)(&(arrayInstance[0])); + } + } + + for(var i = 0; i < 5; i++) { + var maxSigned = Math.pow(2, 8 * Math.pow(2, i) - 1) - 1; + if(i === 3) { + // Floating point fix ;^) + maxSigned /= 1000; + } + + // can't use !== or sizeof(void *) === 0.5 + if(type(maxSigned) != maxSigned) { + return Math.pow(2, i - 1); + } + } + }; + + /* + Logs a specific message sent to an instance of a class like logify.pl in theos + Requires Cydia Substrate (com.saurik.substrate.MS) and NSLog (org.cycript.NSLog) modules + Returns the old message returned by MS.hookMessage (Note: this is not just the old message!) + + Usage: + cy# var oldm = utils.logify(objc_getMetaClass(NSNumber), @selector(numberWithDouble:)) + ... + cy# var n = [NSNumber numberWithDouble:1.5] + 2014-07-28 02:26:39.805 cycript[71213:507] +[ numberWithDouble:1.5] + 2014-07-28 02:26:39.806 cycript[71213:507] = 1.5 + @1.5 + */ + utils.logify = function(cls, sel) { + @import com.saurik.substrate.MS; + @import org.cycript.NSLog; + + var oldm = {}; + + MS.hookMessage(cls, sel, function() { + var args = [].slice.call(arguments); + + var selFormat = sel.toString().replace(/:/g, ":%@ ").trim(); + var logFormat = "%@[<%@: 0x%@> " + selFormat + "]"; + + var standardArgs = [logFormat, class_isMetaClass(cls)? "+": "-", cls.toString(), (&this).valueOf().toString(16)]; + var logArgs = standardArgs.concat(args); + + NSLog.apply(null, logArgs); + + var r = oldm->apply(this, arguments); + + if(r !== undefined) { + NSLog(" = %@", r); + } + + return r; + }, oldm); + + return oldm; + }; + + /* + Calls a C function by providing its name and arguments + Doesn't support structs + Return value is always a void pointer + + Usage: + cy# utils.apply("printf", ["%s %.3s, %d -> %c, float: %f\n", "foo", "barrrr", 97, 97, 1.5]) + foo bar, 97 -> a, float: 1.500000 + 0x22 + */ + utils.apply = function(fun, args) { + if(!(args instanceof Array)) { + throw "Args needs to be an array!"; + } + + var argc = args.length; + var voidPtr = @encode(void *); + var argTypes = []; + for(var i = 0; i < argc; i++) { + var argType = voidPtr; + + var arg = args[i]; + if(typeof arg === "string") { + argType = @encode(char *); + } + if(typeof arg === "number" && arg % 1 !== 0) { + argType = @encode(double); + } + + argTypes.push(argType); + } + + var type = voidPtr.functionWith.apply(voidPtr, argTypes); + + if(typeof fun === "string") { + fun = dlsym(RTLD_DEFAULT, fun); + } + + if(!fun) { + throw "Function not found!"; + } + + return type(fun).apply(null, args); + }; + + /* + Converts a string (char *) to a void pointer (void *) + You can't cast to strings to void pointers and vice versa in cycript. Blame saurik. + + Usage: + cy# var voidPtr = utils.str2voidPtr("foobar") + 0x100331590 + cy# utils.voidPtr2str(voidPtr) + "foobar" + */ + utils.str2voidPtr = function(str) { + var strdup = @encode(void *(char *))(dlsym(RTLD_DEFAULT, "strdup")); + return strdup(str); + }; + + /* + The inverse function of str2voidPtr + */ + utils.voidPtr2str = function(voidPtr) { + var strdup = @encode(char *(void *))(dlsym(RTLD_DEFAULT, "strdup")); + return strdup(voidPtr); + }; + + /* + Converts a double into a void pointer + This can be used to view the binary representation of a floating point number + + Usage: + cy# var n = utils.double2voidPtr(-1.5) + 0xbff8000000000000 + cy# utils.voidPtr2double(n) + -1.5 + */ + utils.double2voidPtr = function(n) { + var doublePtr = new double; + *doublePtr = n; + + var voidPtrPtr = @encode(void **)(doublePtr); + + return *voidPtrPtr; + }; + + /* + The inverse function of double2voidPtr + */ + utils.voidPtr2double = function(voidPtr) { + var voidPtrPtr = new @encode(void **); + *voidPtrPtr = voidPtr; + + var doublePtr = @encode(double *)(voidPtrPtr); + + return *doublePtr; + }; + + /* + Determines in a safe way if a memory location is readable + + Usage: + cy# utils.isMemoryReadable(0) + false + cy# utils.isMemoryReadable(0x1337) + false + cy# utils.isMemoryReadable(NSObject) + true + cy# var a = malloc(100); utils.isMemoryReadable(a) + true + */ + utils.isMemoryReadable = function(ptr) { + if(typeof ptr === "string") { + return true; + } + + var fds = new @encode(int [2]); + utils.apply("pipe", [fds]); + var result = utils.apply("write", [fds[1], ptr, 1]) == 1; + + utils.apply("close", [fds[0]]); + utils.apply("close", [fds[1]]); + + return result; + }; + + /* + Determines in a safe way if the memory location contains an Objective-C object + + Usage: + cy# utils.isObject(0) + false + cy# utils.isObject(0x1337) + false + cy# utils.isObject(NSObject) + true + cy# utils.isObject(objc_getMetaClass(NSObject)) + true + cy# utils.isObject([new NSObject init]) + true + cy# var a = malloc(100); utils.isObject(a) + false + cy# *@encode(void **)(a) = NSObject; utils.isObject(a) + true + */ + utils.isObject = function(obj) { + obj = @encode(void *)(obj); + var lastObj = -1; + + function objc_isa_ptr(obj) { + // See http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html + var objc_debug_isa_class_mask = 0x00000001fffffffa; + obj = (obj & 1)? (obj & objc_debug_isa_class_mask): obj; + + if((obj & (utils.sizeof(@encode(void *)) - 1)) != 0) { + return null; + } else { + return obj; + } + } + + function ptrValue(obj) { + return obj? obj.valueOf(): null; + } + + var foundMetaClass = false; + + for(obj = objc_isa_ptr(obj); utils.isMemoryReadable(obj); ) { + obj = *@encode(void **)(obj); + + if(ptrValue(obj) == ptrValue(lastObj)) { + foundMetaClass = true; + break; + } + + lastObj = obj; + } + + if(!foundMetaClass) { + return false; + } + + if(lastObj === -1 || lastObj === null) { + return false; + } + + var obj_class = objc_isa_ptr(@encode(void **)(obj)[1]); + + if(!utils.isMemoryReadable(obj_class)) { + return false; + } + + var metaclass = objc_isa_ptr(@encode(void **)(obj_class)[0]); + var superclass = objc_isa_ptr(@encode(void **)(obj_class)[1]); + + return ptrValue(obj) == ptrValue(metaclass) && superclass == null; + }; + + /* + Creates a cycript struct type from a C struct definition + + Usage: + cy# var foo = makeStruct("int a; short b; char c; uint64_t d; double e;", "foo"); + @encode(foo) + cy# var f = new foo + &{a:0,b:0,c:0,d:0,e:0} + cy# f->a = 100; f + &{a:100,b:0,c:0,d:0,e:0} + cy# *@encode(int *)(f) + 100 + */ + utils.makeStruct = function(str, name) { + var fieldRe = /(?:\s|\n)*([^;]+\s*(?:\s|\*))([^;]+)\s*;/g; + + if(!name) { + name = "struct" + Math.floor(Math.random() * 100000); + } + var typeStr = "{" + name + "="; + + while((match = fieldRe.exec(str)) !== null) { + var fieldType = utils.applyTypedefs(match[1]); + var fieldName = match[2]; + var encodedType = utils.exec("@encode(" + fieldType + ")").toString(); + + typeStr += '"' + fieldName + '"' + encodedType; + } + + typeStr += "}"; + + return new Type(typeStr); + }; + + // Various constants + utils.constants = { + VM_PROT_NONE: 0x0, + VM_PROT_READ: 0x1, + VM_PROT_WRITE: 0x2, + VM_PROT_EXECUTE: 0x4, + VM_PROT_NO_CHANGE: 0x8, + VM_PROT_COPY: 0x10, + VM_PROT_WANTS_COPY: 0x10, + VM_PROT_IS_MASK: 0x40, + }; + var c = utils.constants; + c.VM_PROT_DEFAULT = c.VM_PROT_READ | c.VM_PROT_WRITE; + c.VM_PROT_ALL = c.VM_PROT_READ | c.VM_PROT_WRITE | c.VM_PROT_EXECUTE; + + if(shouldExposeConsts) { + for(var k in c) { + Cycript.all[k] = c[k]; + } + } + + if(shouldExposeFuncs) { + for(var i = 0; i < funcsToExpose.length; i++) { + var name = funcsToExpose[i]; + Cycript.all[name] = utils[name]; + } + } + + if(shouldLoadCFuncs) { + utils.loadfuncs(shouldExposeCFuncs); + } +})(exports); diff --git a/samples/HTML+ERB/fishbowl.html.erb.deface b/samples/HTML+ERB/fishbowl.html.erb.deface new file mode 100644 index 00000000..43d60cec --- /dev/null +++ b/samples/HTML+ERB/fishbowl.html.erb.deface @@ -0,0 +1,31 @@ + +<% if Spree::Config[:enable_fishbowl] %> +
+
+
+ <%= t(:fishbowl_settings)%> + <% @fishbowl_options.each do |key| %> +
+ <%= label_tag(key, t(key.to_s.gsub('fishbowl_', '').to_sym) + ': ') + tag(:br) %> + <%= text_field_tag('preferences[' + key.to_s + ']', Spree::Config[key], { :size => 10, :class => 'fullwidth' }) %> +
+ <% end %> +
+ <%= hidden_field_tag 'preferences[fishbowl_always_fetch_current_inventory]', '0' %> + <%= check_box_tag('preferences[fishbowl_always_fetch_current_inventory]', "1", Spree::Config[:fishbowl_always_fetch_current_inventory]) %> + <%= t(:always_fetch_current_inventory) %> +
+ <% if !@location_groups.empty? %> +
+ <%= label_tag(:fishbowl_location_group, t(:location_group) + ': ') + tag(:br) %> + <%= select('preferences', 'fishbowl_location_group', @location_groups, { :selected => Spree::Config[:fishbowl_location_group]}, { :class => ['select2', 'fullwidth'] }) %> +
+ <% end %> +
+
+
+ + +<% end %> \ No newline at end of file diff --git a/samples/HTML+ERB/index.html.erb b/samples/HTML+ERB/index.html.erb new file mode 100644 index 00000000..f8888a4b --- /dev/null +++ b/samples/HTML+ERB/index.html.erb @@ -0,0 +1,39 @@ +<% provide(:title, @header) %> +<% present @users do |user_presenter| %> +
+

<%= @header %>

+
+ +
+
+ <%= will_paginate %> +
+
+
+
+
+
Name
+
Email
+
Chords
+
Keys
+
Tunings
+
Credits
+
Prem?
+
Since?
+
+ + <% if @users == [] %> +
+
No Users
+
+ <% else %> + <%= render @users %> + <% end %> +
+
+
+
+ <%= will_paginate %> +
+
+<% end %> \ No newline at end of file diff --git a/samples/Haml/buttons.html.haml.deface b/samples/Haml/buttons.html.haml.deface new file mode 100644 index 00000000..f338721a --- /dev/null +++ b/samples/Haml/buttons.html.haml.deface @@ -0,0 +1,29 @@ +/ + replace '.actions' + +.pull-right + .btn-group + = link_to page.url, target: "_blank", title: t('.view_live_html'), class: "tip btn btn-xs btn-default" do + %i.icon-picture.row-black + + = link_to refinery.edit_admin_page_path(page.nested_url, + switch_locale: (page.translations.first.locale unless page.translated_to_default_locale?)), + title: t('edit', :scope => 'refinery.admin.pages'), + class: "tip btn btn-xs btn-default" do + %i.icon-edit.row-blue + + + - if page.deletable? + = link_to refinery.admin_page_path(page.nested_url), + methode: :delete, + title: t('delete', :scope => 'refinery.admin.pages'), + class: "tip cancel confirm-delete btn btn-xs btn-default", + data: { confirm: t('message', scope: 'refinery.admin.delete', title: page_title_with_translations(page)) } do + %i.icon-trash.row-red + - else + %button.btn.btn-xs.btn-default.disabled + %i.icon-trash + + .btn-group + = link_to refinery.new_admin_page_path(:parent_id => page.id), title: t('new', :scope => 'refinery.admin.pages'), class: "tip btn btn-xs btn-default" do + %i.icon-plus.row-green diff --git a/samples/PHP/filenames/.php b/samples/PHP/filenames/.php new file mode 100755 index 00000000..be170195 --- /dev/null +++ b/samples/PHP/filenames/.php @@ -0,0 +1,34 @@ +#!/usr/bin/env php + diff --git a/samples/XML/filenames/.cproject b/samples/XML/filenames/.cproject new file mode 100755 index 00000000..5fbff7b7 --- /dev/null +++ b/samples/XML/filenames/.cproject @@ -0,0 +1,542 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/test_blob.rb b/test/test_blob.rb index aba82084..54e10030 100644 --- a/test/test_blob.rb +++ b/test/test_blob.rb @@ -140,6 +140,13 @@ class TestBlob < Test::Unit::TestCase assert !blob("Perl/script.pl").binary? end + def test_all_binary + Samples.each do |sample| + blob = blob(sample[:path]) + assert ! (blob.likely_binary? || blob.binary?), "#{sample[:path]} is a binary file" + end + end + def test_text assert blob("Text/README").text? assert blob("Text/dump.sql").text? @@ -185,9 +192,9 @@ class TestBlob < Test::Unit::TestCase assert !blob("Text/README").generated? # Xcode project files - assert blob("XML/MainMenu.xib").generated? + assert !blob("XML/MainMenu.xib").generated? assert blob("Binary/MainMenu.nib").generated? - assert blob("XML/project.pbxproj").generated? + assert !blob("XML/project.pbxproj").generated? # Gemfile.locks assert blob("Gemfile.lock").generated? diff --git a/test/test_language.rb b/test/test_language.rb index 10c5f9a2..7c81ceef 100644 --- a/test/test_language.rb +++ b/test/test_language.rb @@ -167,7 +167,7 @@ class TestLanguage < Test::Unit::TestCase assert_equal 'pot', Language['Gettext Catalog'].search_term assert_equal 'irc', Language['IRC log'].search_term assert_equal 'lhs', Language['Literate Haskell'].search_term - assert_equal 'ruby', Language['Mirah'].search_term + assert_equal 'mirah', Language['Mirah'].search_term assert_equal 'raw', Language['Raw token data'].search_term assert_equal 'bash', Language['Shell'].search_term assert_equal 'vim', Language['VimL'].search_term @@ -249,8 +249,7 @@ class TestLanguage < Test::Unit::TestCase assert_equal Language['Nginx'], Language.find_by_filename('nginx.conf').first assert_equal ['C', 'C++', 'Objective-C'], Language.find_by_filename('foo.h').map(&:name).sort assert_equal [], Language.find_by_filename('rb') - assert_equal [], Language.find_by_filename('.rb') - assert_equal [], Language.find_by_filename('.nkt') + assert_equal [], Language.find_by_filename('.null') assert_equal [Language['Shell']], Language.find_by_filename('.bashrc') assert_equal [Language['Shell']], Language.find_by_filename('bash_profile') assert_equal [Language['Shell']], Language.find_by_filename('.zshrc') diff --git a/test/test_samples.rb b/test/test_samples.rb index e0130282..3ee5b64d 100644 --- a/test/test_samples.rb +++ b/test/test_samples.rb @@ -35,15 +35,33 @@ class TestSamples < Test::Unit::TestCase assert_equal data['tokens_total'], data['language_tokens'].inject(0) { |n, (_, c)| n += c } assert_equal data['tokens_total'], data['tokens'].inject(0) { |n, (_, ts)| n += ts.inject(0) { |m, (_, c)| m += c } } end - + + # Check that there aren't samples with extensions that aren't explicitly defined in languages.yml + def test_parity + extensions = Samples::DATA['extnames'] + languages_yml = File.expand_path("../../lib/linguist/languages.yml", __FILE__) + languages = YAML.load_file(languages_yml) + + languages.each do |name, options| + options['extensions'] ||= [] + + if extnames = extensions[name] + extnames.each do |extname| + next if extname == '.script!' + assert options['extensions'].include?(extname), "#{name} has a sample with extension (#{extname}) that isn't explicitly defined in languages.yml" + end + end + end + end + # If a language extension isn't globally unique then make sure there are samples def test_presence Linguist::Language.all.each do |language| language.all_extensions.each do |extension| language_matches = Language.find_by_filename("foo#{extension}") - + # If there is more than one language match for a given extension - # then check that there are examples for that language with the extension + # then check that there are examples for that language with the extension if language_matches.length > 1 language_matches.each do |language| assert File.directory?("samples/#{language.name}"), "#{language.name} is missing a samples directory"