123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765(* Yoann Padioleau
*
* Copyright (C) 2010-2014 Facebook
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation, with the
* special exception on linking described in file license.txt.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file
* license.txt for more details.
*)openCommonmoduleE=Entity_code(*****************************************************************************)(* Prelude *)(*****************************************************************************)(*
* Emacs-like font-lock-mode, or SourceInsight-like display.
*
* This file contains the generic part of a code highlighter
* that is programming language independent.
* See highlight_xxx.ml for the code specific to the 'xxx'
* programming language.
*
* This source code viewer is based on good semantic information,
* not fragile regexps (as in Emacs), or partial parsing
* (as in SourceInsight, probably because they call cpp).
*
* Augmented visual! Augmented intellect! See what can not see, like in
* movies where HUD show invisible things.
*
* history:
* Some code such as the visitor code was using Emacs_mode_xxx
* visitors before, but now we use directly the raw visitor, cos
* emacs_mode_xxx was not a big win as we must colorize
* and so visit and so get hooks for almost every programming constructs.
*
* Moreover there was some duplication, such as for the different
* categories: I had notes in emacs_mode_xxx and also notes in this file
* about those categories like yacfe_imprecision, cpp, etc. So
* better and cleaner to put all related code in the same file.
*
*
* Why better to have such visualisation ? cf via_pram_readbyte example:
* - better to see that use global via1, and that global to module
* - better to see local macro
* - better to see that some func are local too, the via_pram_writebyte
* - better to see if local, or parameter
* - better to see in comments that important words such as interrupts,
* and 'disabled', and 'must'
*
*
* SEMI do first like gtk source view
* SEMI do first like emacs
* SEMI do like my pad emacs mode extension
* SEMI do for yacfe specific stuff
*
* less: level of font-lock-mode ? so can colorify a lot the current function
* and less the rest (so maybe avoid some of the bugs of GText ?
*
* Take more ideas from Source Insight ?
* - variable size parens depending on depth of nestedness
* - do same for curly braces ?
*
* TODO estet: I often revisit in very similar way the code, and do
* some matching to know if pointercall, methodcall, to know if
* prototype or decl extern, to know if typedef inside, or structdef
* inside. Could
* perhaps define helpers so not redo each time same things ?
*
* estet?: redundant with - place_code ? - entity_c ?
*
* related-work:
* - http://pygments.org/
*)(*****************************************************************************)(* Types helpers *)(*****************************************************************************)(* will be italic vs non-italic (could be large vs small ? or bolder ? *)typeusedef=|Use|Def(* colors will be adjusted (degrade de couleurs) (could also do size? *)typeplace=|PlaceLocal|PlaceSameDir|PlaceExternal(* | ReallyExternal | PlaceCloseHeader *)(* will be in a lighter color, almost like wheat, so know we don't have
* information on it. Could highlight in Red because it's
* quite similar to an error.
*)|NoInfoPlace(* will be underlined or strikedthrough *)typedef_arity=|UniqueDef|DoubleDef|MultiDef|NoDef(* will be different colors *)typeuse_arity=|NoUse|UniqueUse|SomeUse|MultiUse|LotsOfUse|HugeUsetypeuse_info=place*def_arity*use_aritytypedef_info=use_aritytypeusedef2=|Use2ofuse_info|Def2ofdef_info(*****************************************************************************)(* Main type *)(*****************************************************************************)(* coupling: if you add constructor, don't forget to add its
* handling in 2 places below, for its color and associated string
* representation.
*
* If you look at usedef below, you should get all the way C programmer
* can name things:
* - macro, macrovar
* - functions
* - variables (global/param/local)
* - typedefs, structname, enumname, enum, fields
* - labels
* But at the user site, can see only if
* - FunCallOrMacroCall
* - VarOrEnumValOrMacroVar
* - labels
* - field
* - tag (struct, union, enum)
* - typedef
*)(* color, foreground or background will be changed *)typecategory=(* pad's addons (actually Pixel added a special font in Emacs for numbers) *)|Boolean|Number|String|Regexp|Null(* classic emacs mode *)|Keyword(* SEMI multi *)|KeywordConditional|KeywordLoop|KeywordExn|KeywordObject|KeywordModule|Builtin|BuiltinCommentColor(* e.g. for "pr", "pr2", "spf". etc *)|BuiltinBoolean(* e.g. "not" *)|Operator(* TODO multi *)|Punctuation(* Functions, macros, globals, types, ... see Entity_code.entity_kind.
* By default global scope (macro can have local
* but not that used), so no need to like for variables and have a
* global/local dichotomy of scope. (But even if functions are globals,
* still can have some global/local dichotomy but at the module level.
*)|EntityofEntity_code.entity_kind*usedef2(* kind of specific case of Global of Local which we know are really
* really local. Don't really need a def_arity and place here. *)|Localofusedef|Parameterofusedef(* less: could be Entity Prototype, but there is just def for Prototype *)|FunctionDeclofdef_info(* hmm does not fit Constructor use_def, because special kind of use *)|ConstructorMatchofuse_info(* less: use Entity instead? *)|StaticMethodofusedef2|StructNameofusedef|EnumNameofusedef(* ClassName of place ... *)(* special types *)|TypeVoid|TypeInt(* haskell *)|FunctionEquation(* misc *)|Labelofusedef(* semantic information *)|BadSmell(* less: TodoComment? *)(* could reuse Global (Use2 ...) but the use of refs is not always
* the use of a global. Moreover using a ref in OCaml is really bad
* which is why I want to highlight it specially.
*)|UseOfRef|PointerCall(* a.k.a dynamic call *)|CallByRef|ParameterRef|IdentUnknown(* module/cpp related *)|Ifdef|Include|IncludeFilePath|Define|CppOther(* metaprogramming related *)|Attribute(* web related *)|EmbededCode(* e.g. javascript *)|EmbededUrl(* e.g. xhp *)|EmbededHtml(* e.g. xhp *)|EmbededHtmlAttr|EmbededStyle(* e.g. css *)|Verbatim(* for latex, noweb, html pre *)(* comments *)|Comment(* Ccomment *)|CommentWordImportantNotion|CommentWordImportantModal(* pad style specific *)|CommentSection0|CommentSection1|CommentSection2|CommentSection3|CommentSection4|CommentEstet|CommentCopyright|CommentSyncweb(* higher means more important *)|CommentImportance0|CommentImportance1|CommentImportance2(* same than Comment *)|CommentImportance3(* misc *)|GrammarRule(* search and match *)|MatchGlimpse|MatchSmPL|MatchParent|MatchSmPLPositif|MatchSmPLNegatif(* basic *)|BackGround|ForeGround(* parsing imprecision *)|NotParsed|Passed|Expanded|Error|NoType(* well, normal code *)|Normaltypehighlighter_preferences={mutableshow_type_error:bool;mutableshow_local_global:bool;}letdefault_highlighter_preferences={show_type_error=false;show_local_global=true;}(*****************************************************************************)(* Color and font settings *)(*****************************************************************************)(*
* capabilities: (cf also pango.ml)
* - colors, and can provide semantic information by
* * using opposite colors
* * using close colors,
* * using degrade color
* * using tone (darker, brighter)
* * can also use background/foreground
*
* - fontsize
* - bold, italic, slanted, normal
* - underlined/strikedthrough, pango can even do double underlined
* - fontkind, for instance comment could be in a different font
* in addition of different colors ?
* - casse, smallcaps ? (but can confondre avec macro ?)
* - stretch? (condenset)
*
* Recurrent conventions, which would be counter productive to change maybe:
* - string: green
* - keywords: red/orange
*
* Emacs C-mode conventions:
* - entities declarations: light/dark blue
* (dark for param and local, light for func)
* - types: green
* - keywords: orange/dark-orange, this include:
* - control keywords
* - declaration keywords (static/register, but also struct, typedef)
* - cpp builtin keywords
* - labels: cyan
* - entities used: basic
* - comments: grey
* - strings: dark green
*
* pad:
* - punctuation: blue
* - numbers: yellow
*
* semantic variable:
* - global
* - parameter
* - local
* semantic function:
* - local, defined in file
* - global
* - global and multidef
* - global and utilities, so kind of keyword, like my Common.map or
* like kprintf
* semantic types:
* - local/specific
* - globals
* operators:
* - boolean
* - arithmetic
* - bits
* - memory
*
* notions:
* declaration vs use (italic vs non italic, or large vs small)
* type vs values (use color?)
* control vs data (use color?)
* local vs global (bold vs non bold, also can use degarde de couleur)
* module vs program (use font size ?)
* unique vs multi (use underline ? and strikedthrough ?)
*
* more and more distant => darker ?
* less and less unique => bigger ?
* (but both notions of distant and unique are strongly correlated ?)
*
* Normally can leverage indentation and place in file. We know when
* we are not at the toplevel because of the indentation, so can overload
* some colors.
*
*
*
* final:
* (total colors)
* - blanc
* wheat: default (but what remains default??)
* - noir
* gray: comments
*
*
*
* (primary colors)
* - rouge:
* control, conditional vs loop vs jumps, functions
* - bleue:
* variables, values
* - vert:
* types
* - vert-dark: string, chars
*
*
* (secondary colors)
* - jaune (rouge-vert):
* numbers, value
* - magenta (rouge-bleu):
*
* - cyan (vert-bleu):
*
*
* (tertiary colors)
* - orange (rouge-jaune):
*
* - pourpre (rouge-violet)
*
* - rose:
*
* - turquoise:
*
* - marron
*
*)letlegend_color_codes="
The big principles for the colors, fonts, and strikes are:
- italic: for definitions,
normal: for uses
- doubleline: double def,
singleline: multi def,
strike: no def,
normal: single def
- big fonts: use of global variables, or function pointer calls
- lighter: distance of definitions (very light means in same file)
- gray background: not parsed, no type information, or other tool limitations
- red background: expanded code
- other special backgrounds: search results
- green: types
- purple: fields
- yellow: functions (and macros)
- blue: globals, variables
- pink: constants, macros
- cyan and big: global,
turquoise and big: remote global,
dark blue: parameters,
blue: locals
- yellow and big: function pointer,
light yellow: local call (in same file),
dark yellow: remote module call (in same dir)
- salmon: many uses, probably a utility function (e.g. printf)
- red: problem, no definitions
"letinfo_of_usedefusedef=matchusedefwith|Def->[`STYLE`ITALIC]|Use->[]letinfo_of_def_aritydefarity=matchdefaritywith|UniqueDef->[]|DoubleDef->[`UNDERLINE`DOUBLE]|MultiDef->[`UNDERLINE`SINGLE]|NoDef->[`STRIKETHROUGHtrue]letinfo_of_place_defplace=raiseTodoletinfo_of_entity_kind_and_usedef2kinddefkind=matchkind,defkindwith|E.Type,(Def2_)->[`FOREGROUND"chartreuse";]|E.Type,(Use2_)->[`FOREGROUND"chartreuse";]|E.Constructor,(Def2_)->[`FOREGROUND"tomato1";]|E.Constructor,(Use2_)->[`FOREGROUND"pink3";]|E.Module,(Def2_)->[`FOREGROUND"chocolate";]|E.Module,(Use2_)->[`FOREGROUND"DarkSlateGray4";]|E.Field,(Def2_)->[`FOREGROUND"MediumPurple1"]@info_of_usedef(Def)|E.Field,(Use2_)->[`FOREGROUND"MediumPurple2"]@info_of_usedef(Use)|E.Exception,(Def2_)->[`FOREGROUND"Orchid1"]@info_of_usedef(Def)|E.Exception,(Use2_)->[`FOREGROUND"Orchid2"]@info_of_usedef(Use)(* defs *)|E.Function,(Def2_)->[`FOREGROUND"gold";`WEIGHT`BOLD;`STYLE`ITALIC;`SCALE`MEDIUM;]|E.Macro,(Def2_)->[`FOREGROUND"gold";`WEIGHT`BOLD;`STYLE`ITALIC;`SCALE`MEDIUM;]|E.Global,(Def2_)->[`FOREGROUND"cyan";`WEIGHT`BOLD;`STYLE`ITALIC;`SCALE`MEDIUM;]|E.Constant,(Def2_)->[`FOREGROUND"pink";`WEIGHT`BOLD;`STYLE`ITALIC;`SCALE`MEDIUM;]|E.Method,(Def2_)->[`FOREGROUND"gold3";`WEIGHT`BOLD;`SCALE`MEDIUM;]|E.Class,(Def2_)->[`FOREGROUND"coral"]@info_of_usedef(Def)(* uses *)|E.Function,(Use2(defplace,def_arity,use_arity))->(matchdefplacewith|PlaceLocal->[`FOREGROUND"gold";]|PlaceSameDir->[`FOREGROUND"goldenrod";]|PlaceExternal->(matchuse_aritywith|MultiUse->[`FOREGROUND"DarkGoldenrod"]|LotsOfUse|HugeUse|SomeUse->[`FOREGROUND"salmon";]|UniqueUse->[`FOREGROUND"yellow"]|NoUse->[`FOREGROUND"IndianRed";])|NoInfoPlace->[`FOREGROUND"LightGoldenrod";])@info_of_def_aritydef_arity|E.Global,(Use2(defplace,def_arity,use_arity))->[`SCALE`X_LARGE]@(matchdefplacewith|PlaceLocal->[`FOREGROUND"cyan";]|PlaceSameDir->[`FOREGROUND"turquoise3";]|PlaceExternal->(matchuse_aritywith|MultiUse->[`FOREGROUND"turquoise4"]|LotsOfUse|HugeUse|SomeUse->[`FOREGROUND"salmon";]|UniqueUse->[`FOREGROUND"yellow"]|NoUse->[`FOREGROUND"IndianRed";])|NoInfoPlace->[`FOREGROUND"LightCyan";])@info_of_def_aritydef_arity|E.Constant,(Use2(defplace,def_arity,use_arity))->(matchdefplacewith|PlaceLocal->[`FOREGROUND"pink";]|PlaceSameDir->[`FOREGROUND"LightPink";]|PlaceExternal->(matchuse_aritywith|MultiUse->[`FOREGROUND"PaleVioletRed"]|LotsOfUse|HugeUse|SomeUse->[`FOREGROUND"salmon";]|UniqueUse->[`FOREGROUND"yellow"]|NoUse->[`FOREGROUND"IndianRed";])|NoInfoPlace->[`FOREGROUND"pink1";])@info_of_def_aritydef_arity(* copy paste of MacroVarUse for now *)|E.Macro,(Use2(defplace,def_arity,use_arity))->(matchdefplacewith|PlaceLocal->[`FOREGROUND"pink";]|PlaceSameDir->[`FOREGROUND"LightPink";]|PlaceExternal->(matchuse_aritywith|MultiUse->[`FOREGROUND"PaleVioletRed"]|LotsOfUse|HugeUse|SomeUse->[`FOREGROUND"salmon";]|UniqueUse->[`FOREGROUND"yellow"]|NoUse->[`FOREGROUND"IndianRed";])|NoInfoPlace->[`FOREGROUND"pink1";])@info_of_def_aritydef_arity|E.Method,(Use2_)->[`FOREGROUND"gold3";]|E.Class,(Use2_)->[`FOREGROUND"coral"]@info_of_usedef(Use)(* this is for codemap completion search box *)|E.Package,_->[`FOREGROUND"IndianRed"]|E.File,_->[`FOREGROUND"black"](* see dircolors.ml *)|E.Dir,_->[`FOREGROUND"CornFlowerBlue"]|E.MultiDirs,_->[`FOREGROUND"DarkSlateBlue"]|_->failwith(spf"info_of_entity_kind_and_usedef2: missing case for '%s'"(Entity_code.string_of_entity_kindkind))(*****************************************************************************)(* Main entry point *)(*****************************************************************************)(* pad taste *)letinfo_of_category=function(* `FAMILY "-misc-*-*-*-*-20-*-*-*-*-*-*"*)(* `FONT "-misc-fixed-bold-r-normal--13-100-100-100-c-70-iso8859-1" *)(* background *)|BackGround->[`BACKGROUND"DarkSlateGray"]|ForeGround->[`FOREGROUND"wheat";]|NotParsed->[`BACKGROUND"grey42"(*"lightgray"*)]|NoType->[`BACKGROUND"DimGray"]|Passed->[`BACKGROUND"DarkSlateGray4"]|Expanded->[`BACKGROUND"red"]|Error->[`BACKGROUND"red2"](* a flashy one that hurts the eye :) *)|BadSmell->[`FOREGROUND"magenta"]|UseOfRef->[`FOREGROUND"magenta"]|PointerCall->[`FOREGROUND"firebrick";`WEIGHT`BOLD;`SCALE`XX_LARGE;]|ParameterRef->[`FOREGROUND"magenta"]|CallByRef->[`FOREGROUND"orange";`WEIGHT`BOLD;`SCALE`XX_LARGE;]|IdentUnknown->[`FOREGROUND"red";](* searches, background *)|MatchGlimpse->[`BACKGROUND"grey46"]|MatchSmPL->[`BACKGROUND"ForestGreen"]|MatchParent->[`BACKGROUND"blue"]|MatchSmPLPositif->[`BACKGROUND"ForestGreen"]|MatchSmPLNegatif->[`BACKGROUND"red"](* foreground *)|Comment->[`FOREGROUND"gray";]|CommentSection0->[`FOREGROUND"coral";]|CommentSection1->[`FOREGROUND"orange";]|CommentSection2->[`FOREGROUND"LimeGreen";]|CommentSection3->[`FOREGROUND"LightBlue3";]|CommentSection4->[`FOREGROUND"gray";]|CommentEstet->[`FOREGROUND"gray";]|CommentCopyright->[`FOREGROUND"DimGray";]|CommentSyncweb->[`FOREGROUND"DimGray";]|CommentImportance0->[`FOREGROUND"DimGray";]|CommentImportance1->[`FOREGROUND"gray45";]|CommentImportance2->[`FOREGROUND"gray";]|CommentImportance3->[`FOREGROUND"red";](* entities *)|Entity(kind,defkind)->info_of_entity_kind_and_usedef2kinddefkind|FunctionDecl(_)->[`FOREGROUND"gold2";`WEIGHT`BOLD;`STYLE`ITALIC;`SCALE`MEDIUM;]|Parameterusedef->[`FOREGROUND"SteelBlue2";]@info_of_usedefusedef|Localusedef->[`FOREGROUND"SkyBlue1";]@info_of_usedefusedef(* | FunCallMultiDef ->[`FOREGROUND "LightGoldenrod";] *)|StaticMethod(Def2_)->[`FOREGROUND"gold3";`WEIGHT`BOLD;`SCALE`MEDIUM;]|StaticMethod(Use2_)->[`FOREGROUND"gold3";`WEIGHT`BOLD;`SCALE`MEDIUM;]|TypeVoid->[`FOREGROUND"LimeGreen";]|TypeInt->[`FOREGROUND"chartreuse";]|ConstructorMatch_->[`FOREGROUND"pink1";]|FunctionEquation->[`FOREGROUND"LightSkyBlue";]|StructNameusedef->[`FOREGROUND"YellowGreen"]@info_of_usedefusedef|EnumNameusedef->[`FOREGROUND"YellowGreen"]@info_of_usedefusedef|Ifdef->[`FOREGROUND"chocolate";]|Include->[`FOREGROUND"DarkOrange2";]|IncludeFilePath->[`FOREGROUND"SpringGreen3";]|Define->[`FOREGROUND"DarkOrange2";]|CppOther->[`FOREGROUND"DarkOrange2";]|Attribute->[`FOREGROUND"DarkOrange2";]|Keyword->[`FOREGROUND"orange";]|Builtin->[`FOREGROUND"salmon";]|BuiltinCommentColor->[`FOREGROUND"gray";]|BuiltinBoolean->[`FOREGROUND"pink";]|KeywordConditional->[`FOREGROUND"DarkOrange";]|KeywordLoop->[`FOREGROUND"sienna1";]|KeywordExn->[`FOREGROUND"orchid";]|KeywordObject->[`FOREGROUND"aquamarine3";]|KeywordModule->[`FOREGROUND"chocolate";]|Number->[`FOREGROUND"yellow3";]|Boolean->[`FOREGROUND"pink3";]|String->[`FOREGROUND"MediumSeaGreen";]|Regexp->[`FOREGROUND"green3";]|Null->[`FOREGROUND"cyan3";]|CommentWordImportantNotion->[`FOREGROUND"red";`SCALE`LARGE;`UNDERLINE`SINGLE;]|CommentWordImportantModal->[`FOREGROUND"green";`SCALE`LARGE;`UNDERLINE`SINGLE;]|Punctuation->[`FOREGROUND"cyan";]|Operator->[`FOREGROUND"DeepSkyBlue3";](* could do better ? *)|(LabelDef)->[`FOREGROUND"cyan";]|(LabelUse)->[`FOREGROUND"CornflowerBlue";](* to be consistent with Archi_code.Ui color *)|EmbededHtml->[`FOREGROUND"RosyBrown"]|EmbededHtmlAttr->[`FOREGROUND"burlywood3"]|EmbededUrl->(* yellow-like color, like function, because it's often
* used as a method call in method programming
*)[`FOREGROUND"DarkGoldenrod2"]|EmbededCode->[`FOREGROUND"yellow3"]|EmbededStyle->[`FOREGROUND"peru"]|Verbatim->[`FOREGROUND"plum"]|GrammarRule->[`FOREGROUND"plum"]|Normal->[`FOREGROUND"wheat";](*****************************************************************************)(* Generic helpers *)(*****************************************************************************)letarity_idsids=matchidswith|[]->NoDef|[_]->UniqueDef|[_;_]->DoubleDef|_::_::_::_->MultiDefletrewrap_arity_def2_categoryaritycateg=matchcategwith|Entity(kind,(Def2_))->Entity(kind,(Def2arity))|FunctionDecl_->FunctionDecl(arity)|StaticMethod(Def2_)->StaticMethod(Def2arity)|_->failwith"not a Def2-kind categoriy"