Changeset 1438

Show
Ignore:
Timestamp:
07/01/08 21:49:33 (5 months ago)
Author:
rob
Message:

Refs #18: added exuberant ctags parser
* added ShowTagAction? that responds to the fundamental.context_menu message

Location:
trunk/peppy
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • trunk/peppy/lib/userparams.py

    r1434 r1438  
    14601460                    val = getattr(self, param.keyword) 
    14611461                    lines.append("%s = %s" % (param.keyword, param.valueToText(val))) 
    1462                 lines.append("") 
     1462            lines.append("") 
    14631463        text = os.linesep.join(lines) 
    14641464        if self.debuglevel > 0: dprint(text) 
  • trunk/peppy/plugins/project.py

    r1437 r1438  
    1111directory. 
    1212""" 
    13 import os 
     13import os, re 
    1414 
    1515from wx.lib.pubsub import Publisher 
     
    2222 
    2323 
    24 class SaveGlobalTemplate(OnDemandActionNameMixin, SelectAction): 
    25     """Save as the default (application-wide) template for this major mode. 
    26     """ 
    27     name = "Save as Global %s Template" 
    28     default_menu = (("Project/Templates", -700), -100) 
    29  
    30     def getMenuItemName(self): 
    31         return self.__class__.name % self.mode.keyword 
    32  
    33     def action(self, index=-1, multiplier=1): 
    34         pathname = ProjectPlugin.getFilename(self.mode.keyword) 
    35         dprint(pathname) 
    36         self.mode.save(pathname) 
    37  
    38  
    39 class SaveProjectTemplate(OnDemandActionNameMixin, SelectAction): 
    40     """Save as the project template for this major mode. 
    41     """ 
    42     name = "Save as Project %s Template" 
    43     default_menu = (("Project/Templates", -700), 110) 
    44  
    45     def getMenuItemName(self): 
    46         return self.__class__.name % self.mode.keyword 
    47  
    48     def action(self, index=-1, multiplier=1): 
    49         project = ProjectPlugin.findProjectURL(self.mode.buffer.url) 
    50         if project: 
    51             url = project.resolve2(self.mode.keyword) 
    52             self.mode.save(url) 
     24class CTAGS(InstancePrefs): 
     25    default_prefs = ( 
     26        StrParam('ctags_extra_args', '', 'extra arguments for the ctags command', fullwidth=True), 
     27        StrParam('ctags_exclude', '', 'files, directories, or wildcards to exclude', fullwidth=True), 
     28        IndexChoiceParam('tags_file_location', 
     29                         ['project root directory', 'project settings directory'], 
     30                         1, 'Where to store the tags file'), 
     31        ) 
     32     
     33    def loadTags(self): 
     34        if self.tags_file_location == 0: 
     35            base = self.project_top_dir 
    5336        else: 
    54             self.mode.setStatusText("Not in a project.") 
    55  
    56  
    57 class BuildProject(SelectAction): 
    58     """Build the project""" 
    59     name = "Build..." 
    60     icon = 'icons/cog.png' 
    61     default_menu = ("Project", 100) 
    62     key_bindings = {'default': "F7"} 
    63  
    64     def isEnabled(self): 
    65         return bool(ProjectPlugin.getProjectInfo(self.mode)) 
    66  
    67     def action(self, index=-1, multiplier=1): 
    68         project = ProjectPlugin.getProjectInfo(self.mode) 
    69         project.build() 
    70  
    71  
    72 class RunProject(SelectAction): 
    73     """Run the project""" 
    74     name = "Run..." 
    75     icon = 'icons/application.png' 
    76     default_menu = ("Project", 100) 
    77  
    78     def isEnabled(self): 
    79         return bool(ProjectPlugin.getProjectInfo(self.mode)) 
    80  
    81     def action(self, index=-1, multiplier=1): 
    82         project = ProjectPlugin.getProjectInfo(self.mode) 
    83         project.run() 
    84  
    85  
    86 class ProjectSettings(wx.Dialog): 
    87     dialog_title = "Project Settings" 
    88      
    89     def __init__(self, parent, project, title=None): 
    90         if title is None: 
    91             title = self.dialog_title 
    92         wx.Dialog.__init__(self, parent, -1, title, 
    93                            size=(700, 500), pos=wx.DefaultPosition,  
    94                            style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) 
    95  
    96         sizer = wx.BoxSizer(wx.VERTICAL) 
    97          
    98         self.panel = InstancePanel(self, project) 
    99         sizer.Add(self.panel, 1, wx.EXPAND) 
    100          
    101         btnsizer = wx.StdDialogButtonSizer() 
    102          
    103         btn = wx.Button(self, wx.ID_OK) 
    104         btn.SetDefault() 
    105         btnsizer.AddButton(btn) 
    106  
    107         btn = wx.Button(self, wx.ID_CANCEL) 
    108         btnsizer.AddButton(btn) 
    109         btnsizer.Realize() 
    110  
    111         sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 
    112  
    113         self.SetSizer(sizer) 
    114         self.Layout() 
    115      
    116     def applyPreferences(self): 
    117         self.panel.update() 
    118  
    119  
    120 class ShowProjectSettings(SelectAction): 
    121     """Edit project settigns""" 
    122     name = "Project Settings..." 
    123     default_menu = ("Project", -990) 
    124  
    125     def action(self, index=-1, multiplier=1): 
    126         project = ProjectPlugin.getProjectInfo(self.mode) 
    127         if project: 
    128             dlg = ProjectSettings(self.frame, project) 
    129             retval = dlg.ShowModal() 
    130             if retval == wx.ID_OK: 
    131                 dlg.applyPreferences() 
    132  
    133  
    134 class ProjectInfo(InstancePrefs): 
     37            base = self.project_settings_dir 
     38        url = base.resolve2(ProjectPlugin.classprefs.ctags_tag_file_name) 
     39        self.parseCtags(url) 
     40     
     41    def parseCtags(self, filename): 
     42        self.tags = {} 
     43        tagre = re.compile('(.+)\t(.+)\t(.+);"\t(.+)') 
     44        try: 
     45            fh = vfs.open(filename) 
     46            for line in fh: 
     47                match = tagre.match(line) 
     48                if match: 
     49                    tag = match.group(1) 
     50                    file = match.group(2) 
     51                    addr = match.group(3) 
     52                    fields = match.group(4).split('\t') 
     53                    self.dprint("tag=%s file=%s addr=%s field=%s" % (tag, file, addr, str(fields))) 
     54                    if tag not in self.tags: 
     55                        self.tags[tag] = [] 
     56                    self.tags[tag].append((file, addr, fields)) 
     57                    #dprint(self.tags[tag]) 
     58                else: 
     59                    self.dprint(line) 
     60        except Exception, e: 
     61            raise 
     62        dprint(self.tags.keys()) 
     63     
     64    def getTag(self, tag): 
     65        return self.tags.get(tag, None) 
     66 
     67 
     68class ProjectInfo(CTAGS): 
    13569    default_prefs = ( 
    13670        DirParam('build_dir', '', 'working directory in which to build', fullwidth=True), 
     
    14377        self.project_settings_dir = url 
    14478        self.project_top_dir = vfs.get_dirname(url) 
     79        self.project_config = None 
    14580        self.loadPrefs() 
     81        self.loadTags() 
    14682     
    14783    def __str__(self): 
     
    15591     
    15692    def loadPrefs(self): 
    157         url = self.project_settings_dir.resolve2(ProjectPlugin.classprefs.project_file) 
     93        self.project_config = self.project_settings_dir.resolve2(ProjectPlugin.classprefs.project_file) 
    15894        try: 
    159             fh = vfs.open(url) 
     95            fh = vfs.open(self.project_config) 
    16096            if fh: 
    16197                self.readConfig(fh) 
     
    165101        except LookupError: 
    166102            dprint("Project file not found -- using defaults.") 
     103            self.setDefaultPrefs() 
     104     
     105    def savePrefs(self): 
     106        try: 
     107            fh = vfs.open_write(self.project_config) 
     108            text = self.configToText() 
     109            fh.write(text) 
     110        except: 
     111            dprint("Failed writing project config file") 
    167112     
    168113    def build(self): 
     
    171116    def run(self): 
    172117        dprint("Running %s in %s" % (self.run_command, self.run_dir)) 
     118 
     119 
     120##### Actions 
     121 
     122class ShowTagAction(ListAction): 
     123    name = "CTAGS" 
     124    inline = False 
     125    menumax = 20 
     126 
     127    def getItems(self): 
     128        # Because this is a popup action, we can save stuff to this object. 
     129        # Otherwise, we'd save it to the major mode 
     130        if self.mode.project_info: 
     131            lookup = self.mode.check_spelling[0] 
     132            dprint(lookup) 
     133            self.tags = self.mode.project_info.getTag(lookup) 
     134            if self.tags: 
     135                links = [t[0] for t in self.tags] 
     136                return links 
     137        return [_('No suggestions')] 
     138     
     139    def isEnabled(self): 
     140        return bool(self.mode.project_info) and hasattr(self, 'tags') and bool(self.tags) 
     141 
     142    def action(self, index=-1, multiplier=1): 
     143        dprint(self.tags[index]) 
     144 
     145 
     146class SaveGlobalTemplate(OnDemandActionNameMixin, SelectAction): 
     147    """Save as the default (application-wide) template for this major mode. 
     148    """ 
     149    name = "Save as Global %s Template" 
     150    default_menu = (("Project/Templates", -700), -100) 
     151 
     152    def getMenuItemName(self): 
     153        return self.__class__.name % self.mode.keyword 
     154 
     155    def action(self, index=-1, multiplier=1): 
     156        pathname = ProjectPlugin.getFilename(self.mode.keyword) 
     157        dprint(pathname) 
     158        self.mode.save(pathname) 
     159 
     160 
     161class SaveProjectTemplate(OnDemandActionNameMixin, SelectAction): 
     162    """Save as the project template for this major mode. 
     163    """ 
     164    name = "Save as Project %s Template" 
     165    default_menu = (("Project/Templates", -700), 110) 
     166 
     167    def getMenuItemName(self): 
     168        return self.__class__.name % self.mode.keyword 
     169 
     170    def action(self, index=-1, multiplier=1): 
     171        project = ProjectPlugin.findProjectURL(self.mode.buffer.url) 
     172        if project: 
     173            url = project.resolve2(self.mode.keyword) 
     174            self.mode.save(url) 
     175        else: 
     176            self.mode.setStatusText("Not in a project.") 
     177 
     178 
     179class BuildProject(SelectAction): 
     180    """Build the project""" 
     181    name = "Build..." 
     182    icon = 'icons/cog.png' 
     183    default_menu = ("Project", 100) 
     184    key_bindings = {'default': "F7"} 
     185 
     186    def isEnabled(self): 
     187        return bool(ProjectPlugin.getProjectInfo(self.mode)) 
     188 
     189    def action(self, index=-1, multiplier=1): 
     190        project = ProjectPlugin.getProjectInfo(self.mode) 
     191        project.build() 
     192 
     193 
     194class RunProject(SelectAction): 
     195    """Run the project""" 
     196    name = "Run..." 
     197    icon = 'icons/application.png' 
     198    default_menu = ("Project", 100) 
     199 
     200    def isEnabled(self): 
     201        return bool(ProjectPlugin.getProjectInfo(self.mode)) 
     202 
     203    def action(self, index=-1, multiplier=1): 
     204        project = ProjectPlugin.getProjectInfo(self.mode) 
     205        project.run() 
     206 
     207 
     208class ProjectSettings(wx.Dialog): 
     209    dialog_title = "Project Settings" 
     210     
     211    def __init__(self, parent, project, title=None): 
     212        if title is None: 
     213            title = self.dialog_title 
     214        wx.Dialog.__init__(self, parent, -1, title, 
     215                           size=(700, 500), pos=wx.DefaultPosition,  
     216                           style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) 
     217 
     218        sizer = wx.BoxSizer(wx.VERTICAL) 
     219         
     220        self.panel = InstancePanel(self, project) 
     221        sizer.Add(self.panel, 1, wx.EXPAND) 
     222         
     223        btnsizer = wx.StdDialogButtonSizer() 
     224         
     225        btn = wx.Button(self, wx.ID_OK) 
     226        btn.SetDefault() 
     227        btnsizer.AddButton(btn) 
     228 
     229        btn = wx.Button(self, wx.ID_CANCEL) 
     230        btnsizer.AddButton(btn) 
     231        btnsizer.Realize() 
     232 
     233        sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 
     234 
     235        self.SetSizer(sizer) 
     236        self.Layout() 
     237     
     238    def applyPreferences(self): 
     239        self.panel.update() 
     240 
     241 
     242class ShowProjectSettings(SelectAction): 
     243    """Edit project settigns""" 
     244    name = "Project Settings..." 
     245    default_menu = ("Project", -990) 
     246 
     247    def action(self, index=-1, multiplier=1): 
     248        if self.mode.project_info: 
     249            info = self.mode.project_info 
     250            dlg = ProjectSettings(self.frame, info) 
     251            retval = dlg.ShowModal() 
     252            if retval == wx.ID_OK: 
     253                dlg.applyPreferences() 
     254                info.savePrefs() 
    173255 
    174256 
     
    178260        StrParam('project_file', 'project.ini', 'File within project directory used to store per-project information'), 
    179261        StrParam('template_directory', 'templates', 'Directory used to store template files for given major modes'), 
     262        PathParam('ctags_command', 'exuberant-ctags', 'Path to ctags command', fullwidth=True), 
     263        PathParam('ctags_tag_file_name', 'tags', 'name of the generated tags file', fullwidth=True), 
     264        StrParam('ctags_args', '-R ', 'extra arguments for the ctags command', fullwidth=True), 
    180265        ) 
    181266     
     
    193278    def activateHook(self): 
    194279        Publisher().subscribe(self.projectInfo, 'mode.preinit') 
     280        Publisher().subscribe(self.getFundamentalMenu, 'fundamental.context_menu') 
    195281 
    196282    def deactivateHook(self): 
    197283        Publisher().unsubscribe(self.projectInfo) 
     284        Publisher().unsubscribe(self.getFundamentalMenu) 
    198285     
    199286    @classmethod 
     
    238325    def findProjectTemplate(cls, mode): 
    239326        dprint(mode) 
    240         if hasattr(mode, 'project_info'): 
     327        if mode.project_info: 
    241328            url = mode.project_info.getSettingsRelativeURL(cls.classprefs.template_directory) 
    242329            dprint(url) 
     
    284371            mode.project_info = info 
    285372            dprint("found project %s" % info) 
     373        else: 
     374            mode.project_info = None 
    286375     
    287376    @classmethod 
     
    314403        actions.append(ShowProjectSettings) 
    315404        return actions 
     405 
     406    def getFundamentalMenu(self, msg): 
     407        action_classes = msg.data 
     408        action_classes.append(ShowTagAction) 
     409 
     410if __name__== "__main__": 
     411    ctags = ProjectInfo(vfs.normalize("/home/rob/src/peppy-git/.peppy-project")) 
     412    print ctags.getTag('GetValue')