Snapshot 34f078c3452e79ba209d28a551962857e0970e5d from idea/134.1342 of git://git.jetbrains.org/idea/community.git
34f078c: WEB-11147 NPM: Upgrade is disabled for package that was selected before it's version was fetched
caa3d13: Slim. Parser skipps leading comments and line breaks
7b58b81: IDEA-121215 (Java 1.8: "Interface may be annotated with @FunctionalInterface" inspection should not report @interfaces)
4f97ffe: don't reuse progress indicator in ctrl+mouse handler (EA-53958)
95a36c3: IDEA-121294 Toggling breakpoint with a mouse causes unfolding of a section
583c5a7: IDEA-121301 Setting a breakpoint after navigation to a folded method
245f457: cache jar root path
56ca4df: drop memory usage indicator old style
c049454: improve error reporting
72bac20: IDEA-109979 The ability to set breakpoints in the breakpoints edit window
f400bdc: CR-IC-4385 move util method to util
f6ff78b: notnull
847aa41: cleanup
5bd112a: Marking following plugins as broken NodeJS 134.1276 Php 133.982 Ruby 6.0.0.20140207 Karma 134.1163 JSTestDriver 134.1163
aea523f: Cleanup (deprecated code; formatting)
7d90896: Cleanup (missing delegation)
f9371d5: Cleanup (loop invariant; duplicated code)
38269aa: Cleanup (formatting)
7d3368b: java: PsiType documentation corrected
f288bdc: Cleanup (pointless null check; formatting)
d173a3e: IDEA-46403 Breakpoint on an empty line
e0e750e: don't queue breakpoint ui update if nothing changed reuse old CustomizedBreakpointPresentation
0ba4d7e: Gradle description
547cce7: Merge remote-tracking branch 'origin/master'
dff66d2: add JDK statistics
a90591f: Merge branch 'python-fixes'
ae1e6ca: Better error recovery for lines with single 'class' or 'def' keywords and normal functions defined below
10c8b99: support UI state for toggleable selected actions
b1dd00f: icon wrapper for selected toggleable actions' icons
8b4df90: re-think and make it usable in PoppedIcon
83f082f: dispose created marker for good
a39c3b7: Better error recovery for blocks with missing ':' and non-empty bodies
9b8a6cc: Fixed unmached parentheses in test data
9186334: a test for IDEA-116706 Unselect word at caret doesn't work reversing through lambdarized anonymous class
2cb92f2: fix isEnabledCondition
c47a26d: cleanup
60316b6: spelling
4a50ed6: use SmartList
788e5a0: cleanup
628b30a: cleanup
2efcf47: suppress warning
876a793: new test
3f8471c: @Nullable
18f2aee: optimize resolve. In some cases resolve() works faster than resolveGenerics (for example in LiteralClassType) and does not need to infer type parameters which can are needed only after some checks
3f460bc: language level is not @NotNull
37fcda8: simplify code
76d9c82: typo
d85d9f7: lazy inference of closure parameters' types some renames and cleanups
7874795: Disable fullscreen for the sheet parent
88a57a0: Merge remote-tracking branch 'origin/master'
7788a2f: PY-12173 Extract Superclass: warn about conflicting names
0fb4704: diff: fix EditSource action description on toolbar
feaf1fa: fix double icon in available plugins table
c332536: move Sort Installed First to context menu
5ad1016: move Sort by Status to context menu
09bd5b3: Fixed error recovery after empty blocks with no indent
2956e56: PY-12179 Pull up: do not show dialog when there is nothing to pull up
17a06dc: EA-54364 - CCE: SuppressionAnnotationInspectionBase$SuppressionAnnotationVisitor.visitAnnotation
6033fa8: provide type parameter based type with site substitutor to be accepted during type arguments check
2f69c1e: notnull
a575173: moved to community
b8d01ff: CR-IC-4490 Make EnforcedPlainTextFileTypeManager use only project configurations (fixes IDEA-120941)
84279e1: warn only on method parameters
cc9d5bb: IDEA-70465 Multi selection + making it working with live templates
792ea73: WEB-9670 'Surround with Emmet' doesn't work with block selection
1270d02: Live templates and multicaret: stop template at the first variable or end marker
14837f9: Enable multicaret for live templates
6fcc639: IDEA-121193 Don't show 'Class already exists' error if there are two groovy classes with the same qualified name in different modules
6e2687a: CR-IC-4514 @NotNull
2f8c679: cleanup
d4e0fec: Merge remote-tracking branch 'origin/master'
dd8e7fe: Merge branch 'svn_18_3'
78a3523: restored platform prefix autodetection to fix sql tests
5057388: svn: Fixed NPE in SvnConfiguration - initialize inner state to default value
1c5b685: IDEA-95011 diff: better handling of FilesTooBigForDiffException in merge dialog
c599d55: IDEA-121140 Format spock DSL in script body
841e5c6: isRetina fix for headless mode reviewed by kb
685e871: Merge branch 'disable-strings-no-effect'
be10b84: Disable 'Statement has no effect' for all string literals (PY-12194)
ca00903: use embedded tokes for templates instead of injections #WEB-11115 fixed
b671182: Platform: disabled image interpolation on resize in the viewer (IDEA-98635)
f48afb5: Merge remote-tracking branch 'origin/master'
151071e: EA-54197 - IAE: HgTagBranchCommand.collectNames
6a669b7: avoid stripping whitespaces on caret lines on document save (IDEA-80056)
28437d6: diff: fix typo
a10b616: Merge remote-tracking branch 'origin/master'
ea29fa7: Fix incorrect foremost window detection (IDEA-121261).
6e9ac43: Merge branch 'svn_18_3'
9b637e5: for loop -> forEach call chain inspection
e967a04: redundant lambda param types: take site subst into account
994eb2c: junit: do not treat config methods as tests (IDEA-121162)
470d4d0: PY-12213 When moving, members should be sorted according to their dependencies
8f75528: enable new DSM legend for retina & darcula
581f3c4: svn: Refactored SvnConfiguration - settings persistence implemented using PersistentStateComponent<State> class (and not using general PersistentStateComponent<Element> class)
1424a3a: svn: Refactored SvnConfiguration - removed SvnSupportOptions class (logic moved to SvnConfiguration itself)
8d03b3a: Merge remote-tracking branch 'origin/master'
7eb7546: DB props: reuse F4 as part of DataSourceElement.navigate() and drop 'Enter' shortcut
d22be0b: make CaretModelImpl.setCaretsAndSelection() implementation follow contract of interface method (IDEA-80056)
d1752c1: introduce IdeResourcesTestCase: Ultimate & DBE versions
c6d8ea2: Merge remote-tracking branch 'origin/master'
1f69774: NPE fix
5fa2055: Merge branch 'python-live-templates'
76d43e8: WEB-9926 remove 0xhh postfix (property name)
e9c49a1: Added Python live templates for '__main__', 'for' loops, comprehensions, properties (PY-2378)
5e2bf99: IDEA-121202 Step Into doesn't step into a lambda
1be8e04: IDEA-121057 Multiple Carets: Alt-N works in "whole word" mode if the whole word is initially selected
cbbae06: cleanup bean code
b865331: Merge remote-tracking branch 'origin/master'
94b34e9: Merge remote-tracking branch 'origin/master'
6e82d2d: Message header wraps long strings now
e4bb391: IDEA-121227 latest IJ mac builds: Cannot load JVM bundle in case of Java 1.7
138f7f8: Icons improvement
e200179: moved template language setting to the integrated tools
29068e1: png optimization
1686207: Merge branch 'svn_18_3'
a2619760: new debug helpers
7e75d80: Mnemonics
ff028dd: IDEA-103473 Correctly handle paths different only by case on case insensitive file system during commit - use just paths or specialized api for comparison
1ae54aa: IDEA-121099 Ctrl + Shift + Arrows doesn't work with multiple cursors
a578b4a: svn: Use idea home directory as working directory for "move" operation when move paths differ only by case for case insensitive file systems
6aefd30: Resources/Template roots -> Project structure
b8abb8f: add @NotNull to CompletionData.objectToLookupItem
75fdf53: don't choke on non-physical classes in resolve (EA-53892 - IAE: ResolveScopeManagerImpl$.compare)
1d44099: EA-54072 - assert: StubBasedPsiElementBase.getNode
38f2c99: EA-54221 - AIOOBE: ImmutableText.charAt
a717fce: EA-54222 - NPE: TemplateState.setCurrentVariableNumber
0ecb335: IDEA-118988 completion could add 'value=' in annotation
30a899f: add an explanatory comment to com.intellij.ide.macro.EditorMacro.getColumnNumber
e3fde06: use StubIndex.processElements where possible
a91570c: CR-IC-4499: deprecate StubIndex.process, satisfy Maxim's sense of beauty
393b67f: tests repaired
968404a: Merge remote-tracking branch 'origin/master'
6ded813: new inference: most specifics, varargs case
89aefc8: new inference: non-wildcard parameterization
8d60b8d: drop secondary carets when entering/exiting column selection mode (IDEA-80056)
bda5184: Merge remote-tracking branch 'origin/master'
9d41bae: Animator instead of Swing Timer
cddde85: make multi-caret selection with keyboard in column mode work more like old block selection (IDEA-80056)
5601899: Slim formatter started
0826b4a: fix can't read message for IDEA-121207
87ef851: IDEA-121182 Plain text autodetection isn't rerun on file content change
bbd2363: notnull
8248670: notnull
ca9faaa: notnull
1490fb8: moved back to analysis
d2bd356: moved to editor-ui
0b53dbe: IDEA-121220 Focus remains on Document tabs instead of Editor area when tabs switching
34a5343: cleanup
760c3b6: jps plugins to use 1.6 language and bytecode target level
e699813: NodeJS 134.1163 isn't compatible with EAP
e58ef02: Make EditorToggleColumnMode action work with multiple carets like previously with block selection (IDEA-80056)
eb39a65: ensure API backward compatibility
4d26c0a: platform: system notifications reworked
8b2e547: force 1.6 language level for jps-builders
ea1e764: Merge remote-tracking branch 'origin/master'
1b50ea2: lambda -> anonym: disable in unexpected context where cast won't help (IDEA-120165)
f4e209c: lambda -> anonym: additionally process method calls as they may clash with resulted class methods (IDEA-120469)
a745e5a: Merge remote-tracking branch 'origin/master'
b178187: continue gutter layout (don't process all console lines to compute max width)
e521e77: IDEA-111990 Don't close about on blur
82110ac: 1-to-1 mapping between Caret instances for injected and main editors (IDEA-80056)
c074bd2: 1-to-1 mapping between Caret instances for injected and main editors (IDEA-80056)
ff01b5b: get rid of duplicated code in editor fixtures (IDEA-80056)
70aaf37: external build: renamed system property to avoid clashes with user-defined properties for Maven resource filtering (ZD-22524)
78fcfe8: Platform: GenericKeymapManager for IDEs other than IDEA
7589de1: IDEA-2870
64721a2: methods usage index uses mappings
da6e3d8: leave shift + F11 only for bookmarks in JBuilder keymap
ef553f6: IDEA-96651 "Alphabetical order for tabs is ON" warning
e796dc6: make myPressPointScreen accessible in processDragFinish
f130fdc: Merge remote-tracking branch 'origin/master'
ce2d2ec: IDEA-91530 Tab highlighting error when sorted alphabetically
43fdfb2: Spellchecker : IDEA-120568 add gzip (cherry picked from commit 9204f00)
24fbf80: anonym -> lambda: check initializer inside constructor for final fields (IDEA-120698)
44dde64: anonym -> lambda: do not suggest when forward references are detected (IDEA-120699)
b716f47: more consistent highlight "type#selector"
7a9bf2a: reject 1.7 varargs hack as 1.8 reject the code again even with target 1.7
2df995f: More extensibility for CoreProjectEnvironment
b4eba39: move xml descriptors to the module available from Upsource
aa61e88: EA-54181 - NPE: NullableStuffInspectionBase.checkNullableStuffForMethod
f64f1ef: do not suggest broken plugins
7a70428: lambda: accept ellipsis parameter when array expected (IDEA-117124)
d7d0eec: extract method with new inference
351b9b1: tests left on 1.7 for now
8f7ff5b: wrap with command
e0ce9de: testdata
f1b256f: forbid lambda in conditional inside cast context
232f8bd: new inference: strict subtyping: skip raw types
828cb5a: new inference: erase return type if unchecked conversion was performed
01b095b: check myDisposed in read action too
e29d48f: EA-53239 - UOE: VirtualFileImpl.getChildren
9d2947e: IDEA-121192 Fix query construction and update test
92ac042: RemoteSdkCredentials retrieval extracted from RemoteSdkAdditionalData.
17b78eb: show "native" description for node objects
84aa4e8: we must use case-sensitive natural compare — constants must be first, but our naturalCompare is "buggy", so, we perform manual sort before call platform function
5ef006c: WEB-9926 don't auto expand library scope, we must use case-sensitive natural compare — constants must be first
5ac875b: Correct API version is initialized next time JIRA repository is read from settings
4be43ba: WEB-10887 TypeScript: unexpected error occured when Import clause with immediate export
a8c7d79: compact view for installed plugins
a216ae3: DBE: manage data sources action
cd5c3c9: check there are at least 2 tabs are open for move operations
479f584: move to right and move to down actions
0120c91: Generify to support move to right and move to down actions
1cc06ea: text will be assigned automatically
e167ddf: github: fix tests
5a6339b: github: assert -> warning
4edfd8e: remove possible deadlock on network operation in EDT
3d789e3: temporary fix for completion issue (IDEA-80056, EA-54248)
c598b17: @TestOnly
a23a0a6: diff: do not forget about start offset
e17305a: diff: optimise reindexer
0c614ba: IDEA-121031 Plugin Manager: "Update plugin" button does nothing
f32b77f: use install icon and fg/bg on update button
48921af: console gutter component should use setAdditionalColumnsCount now (we use editor area) rename outdated historyAnnotation
32209cb: fix About dialog font on Windows
68e033e: IDEA-121138 Tab completion does not work in autopopup
1c21d1d: Platform: empty text accessor for NewErrorTreeViewPanel
8d25634: DBE: customize editor empty-text ad
a96ee36: fix case in test data file name
5239b11: add help id
e5fe842: better font sizes for Windows and Linux
621a2b3: Git Update tree stays black after switching to Darcula
9d167d2: IDEA-120787 MySQL Comment with Block Comment inside block comment should uncomment; affected for all SelfManagingCommenters
46061a0: introduced REFORMAT_BLOCK_ON_RBRACE property
2d4efe7: project structure dialog: hide library types irrelevant to the current project from 'Global Libraries' -> 'Add' action
9b71864: project structure dialog: hide irrelevant to current module libraries (e.g. JavaScript libraries in Java module) in 'Add Library to dependencies' chooser
1ca73f4: final
3f3e013: simplify ctor
63ec0ea: Merge remote-tracking branch 'origin/master'
17bc69d: added application root to the SDK search path on window (Education Edition attempt)
e26dc5b: IDEA-120157 Reformat code ignores keep dependent methods together order
9173579: new DSM legend
26ff86f: typo
06933eb: IDEA-117902 Commit message wrapping behaves strangely
adaef15: rearrange checkbox in reformat files dialog moved before "only VCS changed text"
e52b01a7: an API to avoid CCEs when doing StubIndex.process
d55d2bb: rename physical->eventSystemEnabled to reduce confusion when constructing FileViewProvider
f786d1e: IDEA-120066 Auto indent on closing curly brace
7f105db: Compilation fix
57ebb86: Cleanup (interface adapter)
3686918: Merge remote-tracking branch 'origin/master'
41624fb: merged
0f39a4c: method refs: restore error on invalid array creation
07de151: AIOOBE
b587af7: exact method refs most specific: void compatibility
527e1de: runSingleTest(Runnable) extracted for parameterized tests
7544243: platform project open processor starts to work as last one, to avoid its interception with SBT / Gradle / Maven / etc (IDEA-121111 )
e37b853: avoid invalid regions
ca5b739: check disposed in read action (EA-53960 - assert: ComponentManagerImpl.getPicoContainer)
307a9b9: github: assertion relaxed for tests
19a1516: Cleanup (pointless exceptions dropped; test reformatted)
dd456d2: Cleanup (typos)
bdf35bd: Cleanup (unneeded cast)
7f5ae7e: Cleanup (formatting)
b877311: Cleanup (unneeded test case inheritance)
d128928: Cleanup (configuration tests correctly generified and annotated)
d9dcac5: Cleanup (typos)
6cc57f8: EA-54183 (CCE: BooleanConstructorInspection$BooleanConstructorFix.doFix)
cf00d70: delete old inference strategy for java 8
96af56c: AIOOBE
2f80e7d: new inference: reject partial computation
72c51dc: configurable oneLineInput
7130e5e: cleanup
c2a4f0d: IDEA-80056 Column selection mode improvement
a5c59c2: github: fix 'open in browser' url
4d7c38f: recover from EA-53754 - IOOBE: CharSequenceSubSequence.<init> (BlockSupportImpl) not only in internal mode
26a4855: hide psiFileFactory
fdee766: IDEA-117332 Change signature refactoring should warn about @Contract conflict
cc56534: IDEA-118094 smart completion in annotation: allow exclude
a3548b0: Fix for focus traversal.
825f767: NPE fix in FormatterTagHandler.getFormatterTag()
ac15549: structure view extracted
9739a4d: javadoc
68c3a40: nullable
53b173e: cleanup
1e7bbca: moved to xml-analysis
7693bbc: cleanup
75ca104: notnull
cad71fe: notnull
e65df65: cleanup
b53845b: notnull
e5df149: moved to core
b4d9fc6: notnull
aa5bc16: moved to core
8e38503: notnull
9a997d1: moved to editor-ui
a816b5d: moved to editor-ui
b1818fc: moved to editor-ui
64b597f: notnull
72e86eb: notnull
a4b1105: cleanup
3c9e26a: removed dependency on FileEditorManager
5f12f65: moved to editor
001957a: moved to core
9f26603: moved to editor-ui
bc83d33: moved to core
745381b: NotNull
4ef4bad: moved to core
ca75131: NPE
4715a42: add file validation on show execution point
09954a9: nodejs doesn't report actual locations after set breakpoint
f97c3ae: nullability
78ef38e: cleanup
6033db3: eliminate WebBrowserBase
0ea4a4b: IDEA-80056 Column selection mode improvement
99dab77: IDEA-80056 Column selection mode improvement
65fc838: Merge remote-tracking branch 'origin/master'
3abd020: fixed NPE
33a6a8c: EA-54164 - assert: FileManagerImpl.findFile
a97592b: Search for unique names that don't clash with anything in mock SDK
569a8ba: Reset module name index in mock SDK setup for reproducible test results
62db067: Merge branch 'python-fixes'
a7e01b8: Don't suggest Python live templates after '.' in qualified names
948ad3e: new inference: ensure type parameters are not modified during ground type evaluation
6a38fba: new inference: avoid current type calculation during conflict resolution for target type detection (IDEA-121052)
edf1d19: don't load modules from disabled plugins
019aa0a: unused field
83a5ada: IDEA-117643 use a correct file for searching for binding variables. Complete binding variables in debugger's watch editor
45c7715: duplicated code
7b9be7e: IDEA-117643 don't add parameters for binding variables. Just try to infer them as they are.
aeb3292: IDEA-119691 Groovy: References to outer class properties should be resolved to accessors if they exist. Fields are prefferable only inside its containing class (not inside inner classes of the outer class)
c41376f: CPP build
add0457: Merge branch 'goto-module'
5897600: Changed the visual representation of PyFileImpl to be more Python module-like (PY-6923)
bdac622: Added Python modules to 'Navigate to class' and 'Navigate to symbol' results (PY-6923)
6c401b1: Added Python module names index (PY-6923)
751a087: EA-46543 (diagnostic)
a91b1d0: Merge remote-tracking branch 'origin/master'
31ea501: grab focus in show all action from interpreter combobox
f6be520: remove association if vEnv associated with different project was selected
6df7c8d: Move GroovyImporter back to org.jetbrains.idea.maven.importing , bacause it used from some plugins.
69b7118: WebBrowserManager API post review
e051d7a: looks like there are a lot of clients assuming default JTable scrollable viewport size (450x400)
8111501: diff: fix action name
8c6f416: IDEA-121050 diff: fix typo
644139e: IDEA-120993 diff: fix diff range calculation in case of newline at the beginning of file
41921f7: diff: rename action
6be4951: diff: add generics
7458f32: github: add assertion
04d6c56: diff: do not fail completely on by-word comparison of two extremely big lines
997c1b2: diff: ask to show content of equal files
74153c9: diff: @Nullable
b285dea: diff: do not call read action to access to local read-only document
7058ea2: IDEA-80056 Column selection mode improvement
fe84447: IDEA-80056 Column selection mode improvement
24763b6: IDEA-121074 Make JIRA remote API version undefined only on actual URL change
964fcf5: java 8: final and default/static in interfaces
d2c3b4b: more specific inference: do not compare functional types if both methods were generic
e42ff74: testdata for IDEA-120992
217a1fd: new inference: address anonymous classes (IDEA-121063)
0f023fa: testdata for IDEA-121055
6900ca8: IDEA-121077 Fix JQL query construction in JIRA connector
d2513fa: java: wrong method used
9fd2a22: groovy: not-so-fast performance test excluded from the suite
6c6ac37: java: ability to skip slow tests
f2ed5a6: Cleanup (platform tests moved to platform)
9c85eb9: Cleanup (dead code; readability; typos; annotations)
0799e8b: Cleanup (common class extracted)
815bba3: pass project to psi file factory
00f817a: LanguageConsoleImpl is not intended to be extended
0b90dc8: add todo note
2c034c0: implement ConsoleJavaScriptInspectionFilter
a38c63c: new inference: isAcceptable for method reference
a4deb4d: new inference: isAcceptable for lambda
de7f053: new inference: do not accept varargs when array is passed there
9fc4b68: new inference: take into account site substitutors during additional constraints gathering
6a5b57d: dispose previous root model when changing to a new one without events
751ec20: save one volatile read on each charAt in editor
5349f1e: language console: revert "disable DaemonCodeAnalyzer "
db3a3d6: Fixed incorrect YesNoCancel behaviour, html in message is handled properly now, size of text in the message is taken into account, esc works properly, better message width and height calculation based on the text area and number of buttons in the message.
c582c37: fix offset calculation remove incorrect call — it is right gutter responsibility
406255c: update notifications about not installed pip/setuptools
fb25259: js repl: setOneLineMode true (will be or not moved as platform default after discussion)
3996201: disable DaemonCodeAnalyzer for console editor — the same as EditorTextField does +review
74f1397: fixing compiler storage data integrity for certain cases when classes are moved between modules
9491e6d: IDEA-120625 Save file as template
1a50247: IDEA-116706 Unselect word at caret doesn't work reversing through lambdarized anonymous class
374e421: IDEA-76185 Macro: $SelectionStartColumn$ and $SelectionEndColumn$ external tools macros count tabs as expanded spaces
4e1ae10: PathMacroMap: add clarifying comments about by-reference string comparison
3510a84: setAdditionalLinesCount = 1
0d4ce76: don't set setRightMarginShown twice — ConsoleViewUtil is enough
a51adfb: LanguageConsoleImpl is not intended to be extended
b792a8c: cleanup
bcaeaeb: cleanup
bbae05d: deprecate createActions — LanguageConsoleImpl is not intended to be extended (actually, it is not used in our code, but we keep method to ensure backward compatibility)
752e268: cleanup
0dbe448: add isEmptyCommandExecutionAllowed, by default true
ec8a5d2: IDEA-80056 Column selection mode improvement
83550bf: Merge remote-tracking branch 'origin/master'
f85aa38: IDEA-120866 Improve usability of 'Uninstall old version(s)' step
ffd542c: CR-IC-4381#c22616
62acb09: Show error message when disable broken plugin.
5a79c28: CR-IC-4381#CFR-71852
90e7243: CR-IC-4381#CFR-71852
a5f7dd7: accidentally committed — revert
3437a1e: optimize imports on project: exception fixed, removed unused method invocation
638f8f1: don't setup delegating color scheme twice — ConsoleViewUtil is enough +review
d785cf6: @NotNull
55e67f6: don't execute empty command
5febcfe: isEmptyOrSpaces accepts CharSequence +review
2610e6c: cleanup
5a83918: deprecate setTextToEditor
975ad62: overrides
c76c841: Merge branch 'master' of git.labs.intellij.net:idea/community
8bd736a: show all in project interpreter combobox regardless virtualenv association
4518cf9: Merge remote-tracking branch 'origin/master'
ce073a75: PY-12196 Members moving refactoring should handle dependencies
b353744: IDEA-120038 - Redesing Git cloud frameworks UI - upload SSH key from account
dbe4736: WEB-11067 Karma Plugin broken because of missing intellijCli Node module
3fb9b1a: fix layout (IDEA-121036)
61bac55: Add "JSTestDriver Plugin" plugin to brokenPlugins.txt
9583062: Postfix completion: do not show 'enable template in autopopup' checkbox if show.template.in.completion.list is enabled
e896024: Postfix completion: apply throw template on Throwable only
79e95dc: Postfix completion: do not apply null, notnull and instanceof template on primitive types
4ddf754: Postfix completion: extract condition constant
1ae8c8c: notnull/nullable
f124013: NPE fix
dc27b12: Add SBT plugin to brokenPlugins.txt
406ebb4: Do not store virtual files in map that is never cleared for IDEA-120732 (Throwable at com.intellij.cvsSupport2.actions.IgnoreFileAction$1.run)
0cfd079: make final
68a8f15: fix CR-PY-5915
5d124b0: fix method isn|'t implemented: com.intellij.execution.console.ProcessBackedConsoleExecuteActionHandler com.intellij.execution.runners.AbstractConsoleRunnerWithHistory#createConsoleExecuteActionHandler() (in Pythonid:3.1.1.134.1462)
52ac45a: deprecate finishExecution()
ce1c1a4: don't expose createConsoleExecAction
c524fb2: cleanup
3ab1740: Merge remote-tracking branch 'origin/master'
cd937d1: better class naming
709bbc0: better class naming
c6ad195: Merge branch 'python-fixes'
4a5c63e: add MarkupModelListener.Adapter
ff1625e: cleanup
8af73b7: Don't resolve to file-level '__metaclass__' in PyClass.getMetaClassExpression() (PY-12127)
abd4c25: IDEA-80056 Column selection mode improvement
14d837e: IDEA-120526 Groovy: Inline super.call()
7065641: IDEA-120979 Static method call in instance context
970da58: fix contracts
4fdbc8c: IDEA-120885: complete 'as' keyword in appropriate place
8342f32: fix JsDebugConfigurationConverterTest
993f8c1: Test fix; cleanup (formatting)
987d9d4: IDEA-120931 Threads tree in "Debugger" pane displays incorrect thread name
9db0214: IDEA-120994 Debugger: tooltip on multiline string value - no need to escape quote characters
ef685df: test fixed
cd39c84: remote templates
3582560: Merge remote-tracking branch 'origin/master'
7de9df1: fixes according code review
59b76f6: suppressed for tests
6a696ee: create project from template: radio button replaced with checkbox
9e8ad70: IDEA-80056 Column selection mode improvement
c1073f8: CR-IC-4035
aa2ed97: Add jira to build in community
b11d66e: new inference: method refs: do not include containing class type params in inference
bac3191: new inferencve: do not apply substitution twice for additional constraints
2a16fd1: new inference: lambda functional type detection
3093e7e: testdata fixed
97b25c1: BaseProgramRunner must be internal
68eb92a: EA-54083 (diagnostic)
0bff0b9: ProcessBackedExecutionEnabledCondition must not be public (and originally was not intended, but we keep backward compatibility)
1b0e049: cleanup
16ae520: ConsoleExecuteActionHandler renamed to ProcessBackedConsoleExecuteActionHandler, keep backward compatibility
b7f131a: ConsoleExecuteActionHandler renamed to ProcessBackedConsoleExecuteActionHandler
415bd34: ConsoleExecuteActionHandler renamed to ProcessBackedConsoleExecuteActionHandler
78a6a8b: remove ruby variant of ConsoleExecuteAction — platform implementation is enough simplification — ConsoleExecuteActionHandler could be also as Condition (we must rename this class to ProcessBackedConsoleExecuteActionHandler — todo)
0912938: cleanup
dec28d2: revert unfinished changes
9495ef2: IDEA-119396 (be picky about unfinished annotated new array expressions)
ead0734: Cleanup (test moved to platform)
3f5ed3f: IDEA-120952
0850b33: Merge remote-tracking branch 'origin/master'
3e4618e: Modify test to attempt to set required initial state, if it's wrong
c068d8e: Fix build due to moved jira module.
eda25d0: Add missing module to layout.gant
9781b1d: IDEA-119819 (Cannot suppress warnings for inspection "Unnecessary unicode escape sequence")
f1f14d5: use setRightMarginShown instead of nullify color +review
8d11adf: overrides
718ee80: IDEA-80056 Column selection mode improvement
62ec1ba: js repl: editor ask us to paint line 4-6, but we should draw line for line 3 (startLine - 1) also, otherwise it will be not rendered fix layout
30e3163: Taking into account Oracle bug 8019291 it is better do not set this property for this transient window than see strange decorations on the transient window.
c814d70: do not embed js into "on" prefixed unknown attributes
3886bc2: Set location of splash screen basing on the current screen device.
f56d570: CR-IC-4445 show whole table by default if it's inside scrollpane
821a6c3: js repl: fix layout
76637d3: LicenseDialog: tuning. LoadingDecorator: rollback
eb161bf: Merge remote-tracking branch 'origin/master'
0c27db7: removed over logging, not informative messages from updater logger.
6abf38a: IDEA-80056 Column selection mode improvement
ed0dc5c: Merge remote-tracking branch 'origin/master'
fbafcac: fixed PY-12186 Project interpreter: not able to select element in appeared settings menu
22da9d4: Updating file properties -> Initializing file system cache (IDEA-115130)
567602b: IDEA-120976 'Complete' work is mentioned 3 times in a simple sentence
4392d23: reverted
089d059: updater: patch applier made tolerant to missing log dir parameter
1305416: zebra-mode enabled
e024d71: WEB-11069 unexpected vertical scrollbar in Bower integration; Review CR-WS-326
d1af527: IDEA-83657 Can't find text in files under .idea
1d9e5df: walk non-indexed files when searching for whole words (IDEA-120648)
09450b1: make go to declaration shortcut also work on console hyperlinks (IDEA-120911)
bfdc9c9: js repl: draw line separators using range marker highlighter
e66c805: EditorEx returns MarkupModelEx (the same as DocumentEx) +review
8efac81: nullability, consistent parameter name
a94a51e: IDEA-120054: Maven: war: non-filtered resource is not copied to output
99ca505: restore clicking on console hyperlinks
f3e9a1e: IDEA-112815 (IDEA does not ignore directories specified in .cvsignore)
85db4a5: use balloon instead of error dialog
713c3d9: cache large leaf element text strings
2f36f24: enable show.live.templates.in.completion by default
16dab5a: IDEA-120911 follow link by keyboard
396d5ec: advance bomb
d0e3130: add jira to tasks plugin
96c8508: remove excessive templates
cbee5a3: clarification
44b16d0: Cleanup (manifest inspections .html files)
54bfa05: new inference: lift also unknown vars (IDEA-117530)
88d220f: new inference: cleanup from eliminateWildcards
e104084: new inference: cleanup checkFunctionalType
1563225: new inference: cleanup from eliminateWildcards
c0f1310: new inference: accept null = Object constraint
1b0e87f: java 8: allow to cast to intersection types
d22feaa: meaningful toString
bd681be: new inference: 18.5.2 adjustments
6103980: bound promotion for super wildcard (? super A (bound extends A) == A)
a91c7f7: bound promotion for super wildcard (? super A (bound extends A) == A)
f3bbc7a: new inference: cleanup
15740a3: new inference: cls copy replacement
4ba1e5f: NPE
1a5e473: AIOOBE
c5d0b16: new inference: debug
555b8b3: new inference: 2 phase resolution
19ba9d8: new inference: resolve
694432f: new inference: capture conversions in return types initial; variable dependencies
758fa4a: rearrange on multiple files continues if no rearranger found for one of them
3e8ca79: IDEA-34877 (CVS: check whether the new-added file name exists in .cvsignore and don't prompt to add it) & IDEA-120736 (CVS: don't prompt to add new-created files ignored using IgnoredFiles list)
10a58c5: Cleanup (extra write action)
1c8930c: Cleanup (double commit)
4f1c289: License Dialog: windows tuning. cleanup
a77da47: LicenseDialog: JetProfile assets choice & proceed
c83ed1d: Merge branch 'svn_18_3'
a472d35: svn: Optimized IdeaCommitHandler - track deleted files only if required (corresponding parameter is set)
045a753: Display conflicts if destination class already has some member
31c7494: let's start async cache update for EAP
342cf54: Merge branch 'svn_18_3'
fbf5d55: js repl: in/out markers done
cf9ace3: svn: Do not check repository protocol (just working copy format) when determining which implementation (SVNKit or command line) should be used for commit operation
ff65c9f: platform: safe project model modification
93b33a3: svn: Refactored SvnCheckinEnvironment - utilize IdeaCommitHandler as event handler for SVNKit commit flow
45cf910: move prepareExecuteAction to LanguageConsoleImpl instance
06062ed: Retina support + no dialog resize (just image clip)
65531b1: fix test data
894d4bb: remove duplicated code — DocumentUtil.writeInRunUndoTransparentAction
effd774: svn: Refactored SvnCheckinEnvironment - use common client factory model for file status detection
c725668: Make BaseRepositoryImpl initialize HTTP client lazily on network settings updates
4af031a: svn: Refactored SvnCheckinEnvironment - not null, code simplifications, methods extracted, warnings fixes
81e72d4: + gruntfile
343a277: revert IDEA-120811
3e991eb: deprecate addCurrentToHistory, cleanup
b22e89b: continue LanguageConsoleBuilder.registerExecuteAction — don't force client to know low-level details, cleanup NewSshConsole
3936b51: add LanguageConsoleBuilder.registerExecuteAction — This API doesn't look good, but it is much better than force client to know low-level details
50318ce: IDEA-120906 NPE at com.intellij.ide.util.projectWizard.SdkSettingsStep.<init>
4524244: Slightly update message in "Option" tab of YouTrack repository editor
cdfd4d0: IDEA-116229 (Invalid Warning: Contents of array 'longs' are written to, but never read)
17dcc98: IDEA-120799 (Quick-fix for "Unnecessary parentheses" changes expression semantics)
0ced324: IDEA-120904 Debugger UI: watch variable text field is shown when debug tool window is hidden
5ed18af: Merge remote-tracking branch 'origin/master'
7d1d9c8: fixed PY-12185 Project interpreter: strange combobox size in settings
7039d82: store 'export to html' settings in workspace.xml instead of shared misc.xml (IDEA-96348)
a3a8fa7: Merge remote-tracking branch 'origin/master'
817df93: Merge remote-tracking branch 'origin/master'
5c95f86: another fix for PY-12186 Project interpreter: not able to select element in appeared settings menu
0c1316c: Merge remote-tracking branch 'origin/master'
ee07119: show word variants in custom file type completion autopopup
f5e8ce0: PathMacroMap: add clarifying comments about by-reference string comparison
f1ac105: use common ExceptionUtil
89e9ca0: do not loose type args on ratianalize static calls (IDEA-120767)
c7b78f7: IDEA-120784 "Class is public should be declared in a file named <Classname>.java" for inner interface
65642d9: IDEA-118305 github: try to fix GH:E specific bug
ada3f52: Merge remote-tracking branch 'origin/master'
3a9eef6: speed search
071a9d5: cleanup
2108e56: fix for PY-12186 Project interpreter: not able to select element in appeared settings menu
11069dc1: Merge remote-tracking branch 'origin/master'
6ec4b86: fixed PY-12184 Project Interpreter: Throwable at com.intellij.openapi.vfs.newvfs.RefreshQueueImpl.execute
08f79dc: diff: do not try to create empty LineFragment
f0eed8c: IDEA-80056 Column selection mode improvement
eec124a: IDEA-80056 Column selection mode improvement
81adc91: IDEA-120834 Same-class methods should be preferred over static imports
1ae2a82: IDEA-118234 Groovy 2.3: type inference of SAM-closure parameters
d0507fc: IDEA-120595 Restore compatibility with JIRA < 4.2. Return support of JIRA SOAP API. Move all JIRA related classes to dedicated module
0fcb597: Add tests for CertificatesManager. Disable them for now, because SNI related patch in httpclient works only on Oracle JRE 1.7+
3355e94: Update Apache HttpClient to 4.3.2 due to fix of HTTPCLIENT-1119
b2d5f76: svn: Refactored AbstractUpdateIntegrateCrawler - remove unnecessary SVNUpdateClient creation
e266021: svn: Refactored GatheringChangelistBuilder - make inherit EmptyChangelistBuilder, renames, optimizations
f042e76: svn: Refactored GatheringChangelistBuilder - use common client factory model to get svn properties (instead of direct SVNWCClient usage)
300839e: svn: Refactored GatheringChangelistBuilder - code simplifications, notnull, removed unused code
17b7bfa: svn: Make SvnKitBrowseClient not pass to handler separate entry for root folder (at which list() method was executed) - to have consistent behaviour for both CmdBrowseClient and SvnKitBrowseClient
c4e1a04f: svn: Implemented correct element name and relative path calculation for CmdBrowseClient
4d8ae08: svn: Refactored SvnChangeList - use common client factory model (instead of direct SVNLogClient usage)
05913e6: svn: Refactored SvnUtil.createUrl - make it throw SvnBindException (instead of SVNException)
8a44f01: svn: Refactored SvnChangeList - SVNRepository usages replaced with "svn info" command
a66c80b: svn: Refactored SvnChangeList - method extractions, code simplifications
56ca50d: svn: Ensure repository relative path is used in SvnChangeList logic (logic was broken and full path was returned after changes in commit 42c824)
58f70a1: svn: Refactored RemoteRevisionsNumberCache - code simplifications, warnings fixes
24e95a4: svn: Refactored SvnCommandLineInfoClient - code simplifications, warnings fixes
87bcdbd: svn: Refactored SvnChangeList - removed duplication, simplified code flow
Change-Id: I25aae09c68ce6c702066c108dae46d17c32e2709
diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml
index f97820d..e402912 100644
--- a/python/src/META-INF/python-core.xml
+++ b/python/src/META-INF/python-core.xml
@@ -89,6 +89,7 @@
<stubIndex implementation="com.jetbrains.python.psi.stubs.PySuperClassIndex"/>
<stubIndex implementation="com.jetbrains.python.psi.stubs.PyVariableNameIndex"/>
<stubIndex implementation="com.jetbrains.python.psi.stubs.PyInstanceAttributeIndex"/>
+ <fileBasedIndex implementation="com.jetbrains.python.psi.stubs.PyModuleNameIndex"/>
<declarationRangeHandler key="com.jetbrains.python.psi.PyClass"
implementationClass="com.jetbrains.python.codeInsight.PyDeclarationRangeHandler"/>
@@ -338,6 +339,7 @@
<liveTemplateMacro implementation="com.jetbrains.python.codeInsight.liveTemplates.CollectionElementNameMacro"/>
<liveTemplateMacro implementation="com.jetbrains.python.codeInsight.liveTemplates.PyClassNameMacro"/>
<liveTemplateMacro implementation="com.jetbrains.python.codeInsight.liveTemplates.PyFunctionNameMacro"/>
+ <liveTemplateMacro implementation="com.jetbrains.python.codeInsight.liveTemplates.PyIterableVariableMacro"/>
<codeInsight.overrideMethod language="Python" implementationClass="com.jetbrains.python.codeInsight.override.PyOverrideMethodsHandler"/>
<lang.refactoringSupport language="Python" implementationClass="com.jetbrains.python.refactoring.PyRefactoringProvider"/>
diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties
index 7bc5469..2e280b4 100644
--- a/python/src/com/jetbrains/python/PyBundle.properties
+++ b/python/src/com/jetbrains/python/PyBundle.properties
@@ -516,6 +516,9 @@
INSP.NAME.assignment.to.loop.or.with.parameter.display.message=Variable ''{0}'' already declared in ''for'' loop or ''with'' statement above
# Refactoring
+refactoring.will.not.be.accessible=Member, you are trying to move depends on ''{0}'' which will not be accessible after this refactoring
+
+
# introduce
refactoring.introduce.name.error=Incorrect name
refactoring.introduce.selection.error=Cannot perform refactoring using selected element(s)
@@ -559,7 +562,8 @@
refactoring.extract.method.error.cannot.perform.refactoring.with.local=Cannot perform refactoring from expression with local variables modifications and return instructions inside code fragment
# extract superclass
-refactoring.extract.super.target.path.outside.roots=Target directory is outside the project.<br>Must be within content roots
+refactoring.extract.super.target.path.outside.roots=Target directory is outside the project. Must be within content roots
+refactoring.extract.super.target.class.already.exists=Class ''{0}'' already exists in this module
refactoring.extract.super.name.0.must.be.ident=Name ''{0}'' is invalid. Must be a valid Python identifier
refactoring.extract.super.class.no.members.allowed=None of members could be extracted
@@ -651,7 +655,7 @@
PARSE.expected.comma.or.rpar=',' or ')' expected
PARSE.expected.else='else' expected
-PARSE.expected.func.name=function name expected
+PARSE.expected.identifier=Identifier expected
PARSE.expected.comma.lpar.rpar=',' or '(' or ')' expected
PARSE.expected.statement.break=Statement break expected
PARSE.expected.@.or.def='@' or 'def' expected
diff --git a/python/src/com/jetbrains/python/PyGotoClassContributor.java b/python/src/com/jetbrains/python/PyGotoClassContributor.java
index 11b759e..2662f66 100644
--- a/python/src/com/jetbrains/python/PyGotoClassContributor.java
+++ b/python/src/com/jetbrains/python/PyGotoClassContributor.java
@@ -19,11 +19,14 @@
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.project.Project;
import com.intellij.util.ArrayUtil;
-import com.jetbrains.python.psi.PyClass;
+import com.intellij.util.containers.HashSet;
import com.jetbrains.python.psi.stubs.PyClassNameIndex;
+import com.jetbrains.python.psi.stubs.PyModuleNameIndex;
import org.jetbrains.annotations.NotNull;
-import java.util.Collection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
/**
* @author yole
@@ -31,13 +34,18 @@
public class PyGotoClassContributor implements ChooseByNameContributor {
@NotNull
public String[] getNames(final Project project, final boolean includeNonProjectItems) {
- final Collection<String> classNames = PyClassNameIndex.allKeys(project);
- return ArrayUtil.toStringArray(classNames);
+ Set<String> results = new HashSet<String>();
+ results.addAll(PyClassNameIndex.allKeys(project));
+ results.addAll(PyModuleNameIndex.getAllKeys(project));
+ return ArrayUtil.toStringArray(results);
}
@NotNull
- public NavigationItem[] getItemsByName(final String name, final String pattern, final Project project, final boolean includeNonProjectItems) {
- final Collection<PyClass> classes = PyClassNameIndex.find(name, project, includeNonProjectItems);
- return classes.toArray(new NavigationItem[classes.size()]);
+ public NavigationItem[] getItemsByName(final String name, final String pattern, final Project project,
+ final boolean includeNonProjectItems) {
+ final List<NavigationItem> results = new ArrayList<NavigationItem>();
+ results.addAll(PyClassNameIndex.find(name, project, includeNonProjectItems));
+ results.addAll(PyModuleNameIndex.find(name, project, includeNonProjectItems));
+ return results.toArray(new NavigationItem[results.size()]);
}
}
diff --git a/python/src/com/jetbrains/python/PyGotoSymbolContributor.java b/python/src/com/jetbrains/python/PyGotoSymbolContributor.java
index 6a283fd..e5eb410 100644
--- a/python/src/com/jetbrains/python/PyGotoSymbolContributor.java
+++ b/python/src/com/jetbrains/python/PyGotoSymbolContributor.java
@@ -25,6 +25,7 @@
import com.jetbrains.python.psi.search.PyProjectScopeBuilder;
import com.jetbrains.python.psi.stubs.PyClassNameIndex;
import com.jetbrains.python.psi.stubs.PyFunctionNameIndex;
+import com.jetbrains.python.psi.stubs.PyModuleNameIndex;
import com.jetbrains.python.psi.stubs.PyVariableNameIndex;
import org.jetbrains.annotations.NotNull;
@@ -41,6 +42,7 @@
public String[] getNames(final Project project, final boolean includeNonProjectItems) {
Set<String> symbols = new HashSet<String>();
symbols.addAll(PyClassNameIndex.allKeys(project));
+ symbols.addAll(PyModuleNameIndex.getAllKeys(project));
symbols.addAll(StubIndex.getInstance().getAllKeys(PyFunctionNameIndex.KEY, project));
symbols.addAll(StubIndex.getInstance().getAllKeys(PyVariableNameIndex.KEY, project));
return ArrayUtil.toStringArray(symbols);
@@ -54,6 +56,7 @@
List<NavigationItem> symbols = new ArrayList<NavigationItem>();
symbols.addAll(PyClassNameIndex.find(name, project, scope));
+ symbols.addAll(PyModuleNameIndex.find(name, project, includeNonProjectItems));
symbols.addAll(PyFunctionNameIndex.find(name, project, scope));
symbols.addAll(PyVariableNameIndex.find(name, project, scope));
diff --git a/python/src/com/jetbrains/python/buildout/BuildoutFacet.java b/python/src/com/jetbrains/python/buildout/BuildoutFacet.java
index eaaa603..e5e607a 100644
--- a/python/src/com/jetbrains/python/buildout/BuildoutFacet.java
+++ b/python/src/com/jetbrains/python/buildout/BuildoutFacet.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -73,7 +73,7 @@
VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() {
@Override
- public void contentsChanged(VirtualFileEvent event) {
+ public void contentsChanged(@NotNull VirtualFileEvent event) {
if (Comparing.equal(event.getFile(), getScript())) {
updatePaths();
attachLibrary(module);
diff --git a/python/src/com/jetbrains/python/codeInsight/liveTemplates/PyIterableVariableMacro.java b/python/src/com/jetbrains/python/codeInsight/liveTemplates/PyIterableVariableMacro.java
new file mode 100644
index 0000000..68eec70
--- /dev/null
+++ b/python/src/com/jetbrains/python/codeInsight/liveTemplates/PyIterableVariableMacro.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.codeInsight.liveTemplates;
+
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.codeInsight.template.*;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiNamedElement;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
+import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
+import com.jetbrains.python.codeInsight.dataflow.scope.Scope;
+import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
+import com.jetbrains.python.psi.PyElement;
+import com.jetbrains.python.psi.PyImportedNameDefiner;
+import com.jetbrains.python.psi.PyTypedElement;
+import com.jetbrains.python.psi.types.PyABCUtil;
+import com.jetbrains.python.psi.types.PyType;
+import com.jetbrains.python.psi.types.TypeEvalContext;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author vlan
+ */
+public class PyIterableVariableMacro extends Macro {
+ @Override
+ public String getName() {
+ return "pyIterableVariable";
+ }
+
+ @Override
+ public String getPresentableName() {
+ return "pyIterableVariable()";
+ }
+
+ @Nullable
+ @Override
+ public Result calculateResult(@NotNull Expression[] params, @NotNull ExpressionContext context) {
+ final PsiElement element = context.getPsiElementAtStartOffset();
+ if (element != null) {
+ final List<PsiNamedElement> components = getIterableElements(element);
+ if (!components.isEmpty()) {
+ return new PsiElementResult(components.get(0));
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public LookupElement[] calculateLookupItems(@NotNull Expression[] params, ExpressionContext context) {
+ final List<LookupElement> results = new ArrayList<LookupElement>();
+ final PsiElement element = context.getPsiElementAtStartOffset();
+ if (element != null) {
+ for (PsiNamedElement iterableElement : getIterableElements(element)) {
+ results.add(LookupElementBuilder.create(iterableElement));
+ }
+ }
+ return results.toArray(new LookupElement[results.size()]);
+ }
+
+ @Override
+ public boolean isAcceptableInContext(TemplateContextType context) {
+ return context instanceof PythonTemplateContextType;
+ }
+
+ @NotNull
+ protected List<PsiNamedElement> getIterableElements(@NotNull PsiElement element) {
+ final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(element.getContainingFile());
+ final List<PsiNamedElement> components = new ArrayList<PsiNamedElement>();
+ for (PsiNamedElement namedElement : getVisibleNamedElements(element)) {
+ if (namedElement instanceof PyTypedElement) {
+ final PyType type = typeEvalContext.getType((PyTypedElement)namedElement);
+ if (type != null && PyABCUtil.isSubtype(type, PyNames.ITERABLE, typeEvalContext)) {
+ components.add(namedElement);
+ }
+ }
+ }
+ return components;
+ }
+
+ @NotNull
+ private static List<PsiNamedElement> getVisibleNamedElements(@NotNull PsiElement anchor) {
+ final List<PsiNamedElement> results = new ArrayList<PsiNamedElement>();
+ for (ScopeOwner owner = ScopeUtil.getScopeOwner(anchor); owner != null; owner = ScopeUtil.getScopeOwner(owner)) {
+ final Scope scope = ControlFlowCache.getScope(owner);
+ results.addAll(scope.getNamedElements());
+ for (PyImportedNameDefiner importedNameDefiner : scope.getImportedNameDefiners()) {
+ for (PyElement importedElement : importedNameDefiner.iterateNames()) {
+ if (importedElement instanceof PsiNamedElement) {
+ results.add((PsiNamedElement)importedElement);
+ }
+ }
+ }
+ }
+ return results;
+ }
+}
diff --git a/python/src/com/jetbrains/python/codeInsight/liveTemplates/PythonTemplateContextType.java b/python/src/com/jetbrains/python/codeInsight/liveTemplates/PythonTemplateContextType.java
index d381562..4ae7abe 100644
--- a/python/src/com/jetbrains/python/codeInsight/liveTemplates/PythonTemplateContextType.java
+++ b/python/src/com/jetbrains/python/codeInsight/liveTemplates/PythonTemplateContextType.java
@@ -16,7 +16,15 @@
package com.jetbrains.python.codeInsight.liveTemplates;
import com.intellij.codeInsight.template.FileTypeBasedContextType;
+import com.intellij.patterns.PsiElementPattern;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.ProcessingContext;
+import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonFileType;
+import org.jetbrains.annotations.NotNull;
+
+import static com.intellij.patterns.PlatformPatterns.psiElement;
/**
* @author yole
@@ -25,4 +33,22 @@
public PythonTemplateContextType() {
super("Python", "Python", PythonFileType.INSTANCE);
}
+
+ @Override
+ public boolean isInContext(@NotNull PsiFile file, int offset) {
+ if (super.isInContext(file, offset)) {
+ final PsiElement element = file.findElementAt(offset);
+ if (element != null) {
+ return !isAfterDot(element);
+ }
+ }
+ return false;
+ }
+
+ private static boolean isAfterDot(@NotNull PsiElement element) {
+ ProcessingContext context = new ProcessingContext();
+ final PsiElementPattern.Capture<PsiElement> capture = psiElement().afterLeafSkipping(psiElement().whitespace(),
+ psiElement().withElementType(PyTokenTypes.DOT));
+ return capture.accepts(element, context);
+ }
}
diff --git a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form
index 5aacd41..b6a71ee 100644
--- a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form
+++ b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.form
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.configuration.PyIntegratedToolsConfigurable">
- <grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="8" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="9" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="657" height="302"/>
@@ -24,12 +24,12 @@
</component>
<vspacer id="fc19e">
<constraints>
- <grid row="7" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+ <grid row="8" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<grid id="728f8" binding="myErrorPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
- <grid row="6" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+ <grid row="7" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -52,7 +52,7 @@
<grid id="e7a5f" binding="myDocStringsPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
- <grid row="2" column="0" row-span="2" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+ <grid row="3" column="0" row-span="2" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -87,7 +87,7 @@
<grid id="9f040" binding="myRestPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
- <grid row="4" column="0" row-span="2" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+ <grid row="5" column="0" row-span="2" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -117,6 +117,20 @@
</component>
</children>
</grid>
+ <component id="a95d2" class="javax.swing.JComboBox" binding="myTemplateLanguage">
+ <constraints>
+ <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ </component>
+ <component id="36fa5" class="javax.swing.JLabel">
+ <constraints>
+ <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text value="Template language:"/>
+ </properties>
+ </component>
</children>
</grid>
</form>
diff --git a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java
index 9637706..63d88c8 100644
--- a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java
+++ b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java
@@ -21,6 +21,12 @@
import com.intellij.facet.ui.FacetConfigurationQuickFix;
import com.intellij.facet.ui.FacetEditorValidator;
import com.intellij.facet.ui.ValidationResult;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.editor.highlighter.EditorHighlighter;
+import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.fileTypes.PlainTextFileType;
@@ -48,6 +54,7 @@
import com.jetbrains.python.documentation.PyDocumentationSettings;
import com.jetbrains.python.packaging.*;
import com.jetbrains.python.sdk.PythonSdkType;
+import com.jetbrains.python.templateLanguages.TemplatesService;
import com.jetbrains.python.testing.PythonTestConfigurationsModel;
import com.jetbrains.python.testing.TestRunnerService;
import com.jetbrains.python.testing.VFSTestFrameworkListener;
@@ -56,6 +63,7 @@
import javax.swing.*;
import java.awt.*;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -77,6 +85,9 @@
private JCheckBox analyzeDoctest;
private JPanel myDocStringsPanel;
private JPanel myRestPanel;
+ private JComboBox myTemplateLanguage;
+ private TemplatesConfigurationsModel myTemplatesModel;
+ private TemplatesService myTemplatesService;
public PyIntegratedToolsConfigurable(@NotNull Module module) {
myModule = module;
@@ -96,6 +107,7 @@
myDocStringsPanel.setBorder(IdeBorderFactory.createTitledBorder("Docstrings"));
myRestPanel.setBorder(IdeBorderFactory.createTitledBorder("reStructuredText"));
+ myTemplatesService = TemplatesService.getInstance(module);
}
@NotNull
@@ -186,6 +198,10 @@
myModel = new PythonTestConfigurationsModel(configurations,
TestRunnerService.getInstance(myModule).getProjectConfiguration(), myModule);
+ List<String> templateConfigurations = TemplatesService.getAllTemplateLanguages();
+ myTemplatesModel = new TemplatesConfigurationsModel(templateConfigurations, myTemplatesService);
+ //noinspection unchecked
+ myTemplateLanguage.setModel(myTemplatesModel);
updateConfigurations();
initErrorValidation();
return myMainPanel;
@@ -215,6 +231,9 @@
if (!getRequirementsPath().equals(myRequirementsPathField.getText())) {
return true;
}
+ if (myTemplateLanguage.getSelectedItem() != myTemplatesModel.getTemplateLanguage()) {
+ return true;
+ }
return false;
}
@@ -223,6 +242,11 @@
if (!Comparing.equal(myDocstringFormatComboBox.getSelectedItem(), myDocumentationSettings.myDocStringFormat)) {
DaemonCodeAnalyzer.getInstance(myProject).restart();
}
+ if (myTemplateLanguage.getSelectedItem() != myTemplatesModel.getTemplateLanguage()) {
+ myTemplatesModel.apply();
+ reparseFiles(Arrays.asList("html", "xml", "js")); //TODO: get from file extensions
+ }
+
if (analyzeDoctest.isSelected() != myDocumentationSettings.analyzeDoctest) {
final List<VirtualFile> files = Lists.newArrayList();
ProjectRootManager.getInstance(myProject).getFileIndex().iterateContent(new ContentIterator() {
@@ -242,25 +266,43 @@
reSTService.setWorkdir(myWorkDir.getText());
if (txtIsRst.isSelected() != reSTService.txtIsRst()) {
reSTService.setTxtIsRst(txtIsRst.isSelected());
- reparseRstFiles();
+ reparseFiles(Collections.singletonList(PlainTextFileType.INSTANCE.getDefaultExtension()));
}
myDocumentationSettings.analyzeDoctest = analyzeDoctest.isSelected();
PyPackageRequirementsSettings.getInstance(myModule).setRequirementsPath(myRequirementsPathField.getText());
DaemonCodeAnalyzer.getInstance(myProject).restart();
}
- public void reparseRstFiles() {
+ public void reparseFiles(final List<String> extensions) {
final List<VirtualFile> filesToReparse = Lists.newArrayList();
ProjectRootManager.getInstance(myProject).getFileIndex().iterateContent(new ContentIterator() {
@Override
public boolean processFile(VirtualFile fileOrDir) {
- if (!fileOrDir.isDirectory() && PlainTextFileType.INSTANCE.getDefaultExtension().equals(fileOrDir.getExtension())) {
+ if (!fileOrDir.isDirectory() && extensions.contains(fileOrDir.getExtension())) {
filesToReparse.add(fileOrDir);
}
return true;
}
});
FileContentUtilCore.reparseFiles(filesToReparse);
+
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+
+ for (Editor editor : EditorFactory.getInstance().getAllEditors()) {
+ if (editor instanceof EditorEx && editor.getProject() == myProject) {
+ final VirtualFile vFile = ((EditorEx)editor).getVirtualFile();
+ if (vFile != null) {
+ final EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(myProject, vFile);
+ ((EditorEx)editor).setHighlighter(highlighter);
+ }
+ }
+ }
+ }
+ });
+
+ DaemonCodeAnalyzer.getInstance(myProject).restart();
}
@Override
@@ -273,6 +315,9 @@
txtIsRst.setSelected(ReSTService.getInstance(myModule).txtIsRst());
analyzeDoctest.setSelected(myDocumentationSettings.analyzeDoctest);
myRequirementsPathField.setText(getRequirementsPath());
+ myTemplateLanguage.setSelectedItem(myTemplatesModel.getTemplateLanguage());
+ myTemplatesModel.reset();
+
}
@Override
diff --git a/python/src/com/jetbrains/python/configuration/TemplatesConfigurationsModel.java b/python/src/com/jetbrains/python/configuration/TemplatesConfigurationsModel.java
new file mode 100644
index 0000000..0722b36
--- /dev/null
+++ b/python/src/com/jetbrains/python/configuration/TemplatesConfigurationsModel.java
@@ -0,0 +1,33 @@
+package com.jetbrains.python.configuration;
+
+import com.intellij.ui.CollectionComboBoxModel;
+import com.jetbrains.python.templateLanguages.TemplatesService;
+
+import java.util.List;
+
+/**
+ * User: catherine
+ */
+public class TemplatesConfigurationsModel extends CollectionComboBoxModel {
+ private String myTemplateLanguage;
+ private final TemplatesService myTemplatesService;
+
+ public TemplatesConfigurationsModel(final List items, TemplatesService templatesService) {
+ super(items, templatesService.getTemplateLanguage());
+ myTemplatesService = templatesService;
+ myTemplateLanguage = myTemplatesService.getTemplateLanguage();
+ }
+
+ public void reset() {
+ setSelectedItem(myTemplateLanguage);
+ }
+
+ public void apply() {
+ myTemplateLanguage = (String)getSelectedItem();
+ myTemplatesService.setTemplateLanguage(myTemplateLanguage);
+ }
+
+ public Object getTemplateLanguage() {
+ return myTemplateLanguage;
+ }
+}
\ No newline at end of file
diff --git a/python/src/com/jetbrains/python/console/PyOpenDebugConsoleAction.java b/python/src/com/jetbrains/python/console/PyOpenDebugConsoleAction.java
index 3f4e801..45906d5 100644
--- a/python/src/com/jetbrains/python/console/PyOpenDebugConsoleAction.java
+++ b/python/src/com/jetbrains/python/console/PyOpenDebugConsoleAction.java
@@ -22,7 +22,6 @@
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.IdeFocusManager;
@@ -53,6 +52,7 @@
}
}
+ @Override
public void actionPerformed(final AnActionEvent e) {
final Project project = e.getData(CommonDataKeys.PROJECT);
if (project != null) {
diff --git a/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java b/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java
index 809d957..b4d8360 100644
--- a/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java
+++ b/python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.java
@@ -18,8 +18,8 @@
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.execution.console.LanguageConsoleImpl;
import com.intellij.execution.console.LanguageConsoleView;
+import com.intellij.execution.console.ProcessBackedConsoleExecuteActionHandler;
import com.intellij.execution.process.ProcessHandler;
-import com.intellij.execution.runners.ConsoleExecuteActionHandler;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
@@ -43,7 +43,7 @@
/**
* @author traff
*/
-public class PydevConsoleExecuteActionHandler extends ConsoleExecuteActionHandler implements ConsoleCommunicationListener {
+public class PydevConsoleExecuteActionHandler extends ProcessBackedConsoleExecuteActionHandler implements ConsoleCommunicationListener {
private final LanguageConsoleView myConsoleView;
private String myInMultilineStringState = null;
@@ -293,7 +293,7 @@
setCurrentIndentSize(1);
}
- @Override
+ @SuppressWarnings({"override", "deprecation"})
public void finishExecution() {
final LanguageConsoleImpl console = myConsoleView.getConsole();
final Editor currentEditor = console.getConsoleEditor();
diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
index e7952a3..213f635 100644
--- a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
+++ b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java
@@ -23,12 +23,12 @@
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.console.ConsoleHistoryController;
import com.intellij.execution.console.LanguageConsoleView;
+import com.intellij.execution.console.ProcessBackedConsoleExecuteActionHandler;
import com.intellij.execution.process.CommandLineArgumentsProvider;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.execution.runners.AbstractConsoleRunnerWithHistory;
-import com.intellij.execution.runners.ConsoleExecuteActionHandler;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.*;
@@ -54,7 +54,7 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.FileElement;
-import com.intellij.remotesdk.RemoteSdkData;
+import com.intellij.remotesdk.RemoteSdkCredentials;
import com.intellij.remotesdk.RemoteSshProcess;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.ArrayUtil;
@@ -77,6 +77,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
@@ -91,6 +92,7 @@
*/
public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonConsoleView> {
private static final Logger LOG = Logger.getInstance(PydevConsoleRunner.class.getName());
+ @SuppressWarnings("SpellCheckingInspection")
public static final String PYDEV_PYDEVCONSOLE_PY = "pydev/pydevconsole.py";
public static final int PORTS_WAITING_TIMEOUT = 20000;
@@ -188,6 +190,7 @@
@Override
public void run() {
ProgressManager.getInstance().run(new Task.Backgroundable(getProject(), "Connecting to console", false) {
+ @Override
public void run(@NotNull final ProgressIndicator indicator) {
indicator.setText("Connecting to console...");
try {
@@ -195,6 +198,7 @@
}
catch (ExecutionException e) {
LOG.warn("Error running console", e);
+ assert myProject != null;
ExecutionHelper.showErrors(myProject, Arrays.<Exception>asList(e), getTitle(), null);
}
}
@@ -247,14 +251,17 @@
args.add(String.valueOf(port));
}
return new CommandLineArgumentsProvider() {
+ @Override
public String[] getArguments() {
return ArrayUtil.toStringArray(args);
}
+ @Override
public boolean passParentEnvs() {
return false;
}
+ @Override
public Map<String, String> getAdditionalEnvs() {
return addDefaultEnvironments(sdk, environmentVariables);
}
@@ -295,7 +302,7 @@
private Process createRemoteConsoleProcess(PythonRemoteInterpreterManager manager, String[] command, Map<String, String> env)
throws ExecutionException {
- RemoteSdkData data = (RemoteSdkData)mySdk.getSdkAdditionalData();
+ RemoteSdkCredentials data = (RemoteSdkCredentials)mySdk.getSdkAdditionalData();
assert data != null;
GeneralCommandLine commandLine = new GeneralCommandLine(command);
@@ -348,7 +355,7 @@
try {
return Integer.parseInt(line);
}
- catch (NumberFormatException e) {
+ catch (NumberFormatException ignored) {
continue;
}
}
@@ -357,7 +364,7 @@
Thread.sleep(200);
}
- catch (InterruptedException e1) {
+ catch (InterruptedException ignored) {
}
if (process.exitValue() != 0) {
@@ -365,7 +372,7 @@
try {
error = "Console process terminated with error:\n" + StreamUtil.readText(process.getErrorStream());
}
- catch (Exception e) {
+ catch (Exception ignored) {
error = "Console process terminated with exit code " + process.exitValue();
}
throw new ExecutionException(error);
@@ -447,7 +454,7 @@
e.getPresentation().setEnabled(enabled);
}
};
- anAction.registerCustomShortcutSet(KeyEvent.VK_C, KeyEvent.CTRL_MASK, getConsoleView().getConsole().getConsoleEditor().getComponent());
+ anAction.registerCustomShortcutSet(KeyEvent.VK_C, InputEvent.CTRL_MASK, getConsoleView().getConsole().getConsoleEditor().getComponent());
anAction.getTemplatePresentation().setVisible(false);
return anAction;
}
@@ -458,7 +465,8 @@
@Override
public void actionPerformed(final AnActionEvent e) {
new WriteCommandAction(getLanguageConsole().getProject(), getLanguageConsole().getFile()) {
- protected void run(final Result result) throws Throwable {
+ @Override
+ protected void run(@NotNull final Result result) throws Throwable {
String text = getLanguageConsole().getEditorDocument().getText();
String newText = text.substring(0, text.length() - myConsoleExecuteActionHandler.getPythonIndent());
getLanguageConsole().getEditorDocument().setText(newText);
@@ -495,7 +503,7 @@
try {
res = myPydevConsoleCommunication.handshake();
}
- catch (XmlRpcException e) {
+ catch (XmlRpcException ignored) {
res = false;
}
if (res) {
@@ -510,7 +518,7 @@
try {
Thread.sleep(100);
}
- catch (InterruptedException e) {
+ catch (InterruptedException ignored) {
}
}
}
@@ -549,7 +557,7 @@
// waiting for REPL communication before destroying process handler
Thread.sleep(300);
}
- catch (Exception e1) {
+ catch (Exception ignored) {
// Ignore
}
generalStopAction.actionPerformed(furtherActionEvent);
@@ -568,7 +576,7 @@
@NotNull
@Override
- protected ConsoleExecuteActionHandler createConsoleExecuteActionHandler() {
+ protected ProcessBackedConsoleExecuteActionHandler createExecuteActionHandler() {
myConsoleExecuteActionHandler =
new PydevConsoleExecuteActionHandler(getConsoleView(), getProcessHandler(), myPydevConsoleCommunication);
myConsoleExecuteActionHandler.setEnabled(false);
@@ -673,8 +681,9 @@
@Override
public void run(@NotNull ProgressIndicator indicator) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
+ @Override
public void run() {
- PydevConsoleRunner.this.closeCommunication();
+ closeCommunication();
}
});
diff --git a/python/src/com/jetbrains/python/console/PythonConsoleView.java b/python/src/com/jetbrains/python/console/PythonConsoleView.java
index a815e68..a32f3fc 100644
--- a/python/src/com/jetbrains/python/console/PythonConsoleView.java
+++ b/python/src/com/jetbrains/python/console/PythonConsoleView.java
@@ -77,12 +77,21 @@
private final LanguageConsoleViewImpl myLanguageConsoleView;
- private Disposable mySplittedDisposable;
+ private Disposable mySplitDisposable;
- public PythonConsoleView(final Project project, final String title, Sdk sdk) {
+ public PythonConsoleView(final Project project, final String title, final Sdk sdk) {
super(new BorderLayout());
- myLanguageConsoleView = new LanguageConsoleViewImpl(new PythonLanguageConsole(project, title, sdk));
+ LanguageConsoleImpl languageConsole = new LanguageConsoleImpl(project, title, PythonLanguage.getInstance(), false);
+ if (languageConsole.getFile().getVirtualFile() != null) {
+ languageConsole.getFile().getVirtualFile().putUserData(LanguageLevel.KEY, PythonSdkType.getLanguageLevelForSdk(sdk));
+ }
+ // Mark editor as console one, to prevent autopopup completion
+ languageConsole.getConsoleEditor().putUserData(PythonConsoleAutopopupBlockingHandler.REPL_KEY, new Object());
+ languageConsole.setShowSeparatorLine(PyConsoleOptions.getInstance(project).isShowSeparatorLine());
+ languageConsole.initComponents();
+
+ myLanguageConsoleView = new LanguageConsoleViewImpl(languageConsole);
add(myLanguageConsoleView.getComponent(), BorderLayout.CENTER);
@@ -96,7 +105,7 @@
}
public void setConsoleCommunication(final ConsoleCommunication communication) {
- getPythonLanguageConsole().setConsoleCommunication(communication);
+ getPythonLanguageConsole().getFile().putCopyableUserData(PydevConsoleRunner.CONSOLE_KEY, communication);
}
public void setExecutionHandler(@NotNull PydevConsoleExecuteActionHandler consoleExecuteActionHandler) {
@@ -110,8 +119,8 @@
getLanguageConsole().getHistoryViewer().getComponent().updateUI();
}
- private PythonLanguageConsole getPythonLanguageConsole() {
- return ((PythonLanguageConsole)getLanguageConsole());
+ private LanguageConsoleImpl getPythonLanguageConsole() {
+ return getLanguageConsole();
}
public LanguageConsoleImpl getLanguageConsole() {
@@ -165,11 +174,11 @@
public void run() {
String text = getPythonLanguageConsole().getConsoleEditor().getDocument().getText();
- getPythonLanguageConsole().setTextToEditor(code);
+ getPythonLanguageConsole().setInputText(code);
myExecuteActionHandler.runExecuteAction(myLanguageConsoleView);
if (!StringUtil.isEmpty(text)) {
- getPythonLanguageConsole().setTextToEditor(text);
+ getPythonLanguageConsole().setInputText(text);
}
}
});
@@ -348,7 +357,7 @@
}
public void setSdk(Sdk sdk) {
- getPythonLanguageConsole().setSdk(sdk);
+ getPythonLanguageConsole().getFile().putCopyableUserData(PydevConsoleRunner.CONSOLE_SDK, sdk);
}
@Override
@@ -403,7 +412,7 @@
removeAll();
JSplitPane p = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
p.add(myLanguageConsoleView.getComponent(), JSplitPane.LEFT);
- mySplittedDisposable = componentDisposable;
+ mySplitDisposable = componentDisposable;
p.add(component, JSplitPane.RIGHT);
p.setDividerLocation((int)getSize().getWidth()*2/3);
add(p, BorderLayout.CENTER);
@@ -417,38 +426,9 @@
add(myLanguageConsoleView.getComponent(), BorderLayout.CENTER);
validate();
repaint();
- if (mySplittedDisposable != null) {
- Disposer.dispose(mySplittedDisposable);
- mySplittedDisposable = null;
- }
- }
-
- private static class PythonLanguageConsole extends LanguageConsoleImpl {
-
- public PythonLanguageConsole(final Project project, final String title, final Sdk sdk) {
- super(project, title, PythonLanguage.getInstance(), false);
- initLanguageLevel(sdk);
- // Mark editor as console one, to prevent autopopup completion
- getConsoleEditor().putUserData(PythonConsoleAutopopupBlockingHandler.REPL_KEY, new Object());
-
- setShowSeparatorLine(PyConsoleOptions.getInstance(project).isShowSeparatorLine());
-
- initComponents();
- }
-
- private void initLanguageLevel(@Nullable Sdk sdk) {
- if (myFile.getVirtualFile() != null) {
- //noinspection ConstantConditions
- myFile.getVirtualFile().putUserData(LanguageLevel.KEY, PythonSdkType.getLanguageLevelForSdk(sdk));
- }
- }
-
- public void setConsoleCommunication(final ConsoleCommunication communication) {
- myFile.putCopyableUserData(PydevConsoleRunner.CONSOLE_KEY, communication);
- }
-
- public void setSdk(Sdk sdk) {
- myFile.putCopyableUserData(PydevConsoleRunner.CONSOLE_SDK, sdk);
+ if (mySplitDisposable != null) {
+ Disposer.dispose(mySplitDisposable);
+ mySplitDisposable = null;
}
}
}
diff --git a/python/src/com/jetbrains/python/console/PythonDebugLanguageConsoleView.java b/python/src/com/jetbrains/python/console/PythonDebugLanguageConsoleView.java
index b807b3c..495c26d 100644
--- a/python/src/com/jetbrains/python/console/PythonDebugLanguageConsoleView.java
+++ b/python/src/com/jetbrains/python/console/PythonDebugLanguageConsoleView.java
@@ -63,7 +63,7 @@
public PythonDebugLanguageConsoleView(final Project project, Sdk sdk, ConsoleView consoleView) {
super(new CardLayout());
- myPydevConsoleView = createConsoleView(project, sdk);
+ myPydevConsoleView = new PythonConsoleView(project, "Python Console", sdk);
myTextConsole = consoleView;
add(myTextConsole.getComponent(), TEXT_CONSOLE_PANEL);
@@ -85,10 +85,6 @@
getPydevConsoleView().executeCode(code, e);
}
- private static PythonConsoleView createConsoleView(Project project, Sdk sdk) {
- return new PythonConsoleView(project, "Python Console", sdk);
- }
-
private void doShowConsole(String type) {
CardLayout cl = (CardLayout)(getLayout());
cl.show(this, type);
diff --git a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java
index c21288e..9c610e7 100644
--- a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java
+++ b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java
@@ -23,7 +23,6 @@
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.LangDataKeys;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
@@ -36,7 +35,7 @@
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.PathMappingSettings;
import com.jetbrains.python.buildout.BuildoutFacet;
-import com.jetbrains.python.remote.PyRemoteSdkData;
+import com.jetbrains.python.remote.PyRemoteSdkCredentials;
import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
import com.jetbrains.python.run.PythonCommandLineState;
import com.jetbrains.python.sdk.PySdkUtil;
@@ -154,7 +153,7 @@
PythonRemoteInterpreterManager instance = PythonRemoteInterpreterManager.getInstance();
if (instance != null) {
mappingSettings =
- instance.setupMappings(project, (PyRemoteSdkData)sdk.getSdkAdditionalData(), null);
+ instance.setupMappings(project, (PyRemoteSdkCredentials)sdk.getSdkAdditionalData(), null);
}
}
return mappingSettings;
diff --git a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java
index c6db6ba..3199200 100644
--- a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java
+++ b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java
@@ -40,7 +40,6 @@
import com.jetbrains.python.console.PythonConsoleView;
import com.jetbrains.python.console.PythonDebugConsoleCommunication;
import com.jetbrains.python.console.PythonDebugLanguageConsoleView;
-import com.jetbrains.python.console.pydev.ConsoleCommunication;
import com.jetbrains.python.run.AbstractPythonRunConfiguration;
import com.jetbrains.python.run.CommandLinePatcher;
import com.jetbrains.python.run.PythonCommandLineState;
@@ -58,24 +57,29 @@
public class PyDebugRunner extends GenericProgramRunner {
public static final String PY_DEBUG_RUNNER = "PyDebugRunner";
+ @SuppressWarnings("SpellCheckingInspection")
public static final String DEBUGGER_MAIN = "pydev/pydevd.py";
public static final String CLIENT_PARAM = "--client";
public static final String PORT_PARAM = "--port";
public static final String FILE_PARAM = "--file";
public static final String PYCHARM_PROJECT_ROOTS = "PYCHARM_PROJECT_ROOTS";
+ @SuppressWarnings("SpellCheckingInspection")
public static final String GEVENT_SUPPORT = "GEVENT_SUPPORT";
+ @Override
@NotNull
public String getRunnerId() {
return PY_DEBUG_RUNNER;
}
+ @Override
public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) {
return DefaultDebugExecutor.EXECUTOR_ID.equals(executorId) &&
profile instanceof AbstractPythonRunConfiguration &&
((AbstractPythonRunConfiguration)profile).canRunWithCoverage();
}
+ @Override
protected RunContentDescriptor doExecute(@NotNull final Project project, @NotNull RunProfileState profileState,
RunContentDescriptor contentToReuse,
@NotNull ExecutionEnvironment env) throws ExecutionException {
@@ -89,6 +93,7 @@
final XDebugSession session = XDebuggerManager.getInstance(project).
startSession(this, env, contentToReuse, new XDebugProcessStarter() {
+ @Override
@NotNull
public XDebugProcess start(@NotNull final XDebugSession session) {
PyDebugProcess pyDebugProcess =
@@ -117,19 +122,14 @@
@NotNull final ExecutionResult result,
@NotNull PyDebugProcess debugProcess) {
ExecutionConsole console = result.getExecutionConsole();
- ProcessHandler processHandler = result.getProcessHandler();
-
if (console instanceof PythonDebugLanguageConsoleView) {
PythonConsoleView pythonConsoleView = ((PythonDebugLanguageConsoleView)console).getPydevConsoleView();
+ pythonConsoleView.setConsoleCommunication(new PythonDebugConsoleCommunication(project, debugProcess));
-
- ConsoleCommunication consoleCommunication = new PythonDebugConsoleCommunication(project, debugProcess);
- pythonConsoleView.setConsoleCommunication(consoleCommunication);
-
+ ProcessHandler processHandler = result.getProcessHandler();
PydevDebugConsoleExecuteActionHandler consoleExecuteActionHandler = new PydevDebugConsoleExecuteActionHandler(pythonConsoleView,
processHandler,
- consoleCommunication);
-
+ new PythonDebugConsoleCommunication(project, debugProcess));
pythonConsoleView.setExecutionHandler(consoleExecuteActionHandler);
debugProcess.getSession().addSessionListener(consoleExecuteActionHandler);
@@ -156,9 +156,8 @@
final PythonCommandLineState pyState,
final int serverLocalPort) {
return new CommandLinePatcher() {
+ @Override
public void patchCommandLine(GeneralCommandLine commandLine) {
-
-
// script name is the last parameter; all other params are for python interpreter; insert just before name
final ParametersList parametersList = commandLine.getParametersList();
@@ -170,11 +169,13 @@
final PythonSdkFlavor flavor = pyState.getSdkFlavor();
if (flavor != null) {
+ assert exeParams != null;
for (String option : flavor.getExtraDebugOptions()) {
exeParams.addParameter(option);
}
}
+ assert debugParams != null;
fillDebugParameters(project, debugParams, serverLocalPort, pyState, commandLine);
}
};
@@ -187,6 +188,7 @@
@NotNull GeneralCommandLine generalCommandLine) {
debugParams.addParameter(PythonHelpersLocator.getHelperPath(DEBUGGER_MAIN));
if (pyState.isMultiprocessDebug()) {
+ //noinspection SpellCheckingInspection
debugParams.addParameter("--multiproc");
}
diff --git a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java
index 5aec8ce..28ccafd 100644
--- a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java
@@ -21,8 +21,6 @@
import com.intellij.psi.ResolveResult;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.PyBundle;
-import com.jetbrains.python.documentation.DocStringUtil;
-import com.jetbrains.python.inspections.quickfix.StatementEffectDocstringQuickFix;
import com.jetbrains.python.inspections.quickfix.StatementEffectFunctionCallQuickFix;
import com.jetbrains.python.inspections.quickfix.StatementEffectIntroduceVariableQuickFix;
import com.jetbrains.python.psi.*;
@@ -66,6 +64,11 @@
return;
if (hasEffect(expression)) return;
+ // https://twitter.com/gvanrossum/status/112670605505077248
+ if (expression instanceof PyStringLiteralExpression) {
+ return;
+ }
+
final PyTryPart tryPart = PsiTreeUtil.getParentOfType(node, PyTryPart.class);
if (tryPart != null) {
final PyStatementList statementList = tryPart.getStatementList();
@@ -76,9 +79,6 @@
return;
}
}
- if (checkStringLiteral(expression)) {
- return;
- }
if (expression instanceof PyReferenceExpression && !((PyReferenceExpression)expression).isQualified()) {
registerProblem(expression, PyBundle.message("INSP.NAME.statement.message"));
}
@@ -87,18 +87,6 @@
}
}
- private boolean checkStringLiteral(PyExpression expression) {
- if (expression instanceof PyStringLiteralExpression) {
- PyDocStringOwner parent = PsiTreeUtil.getParentOfType(expression, PyFunction.class, PyClass.class);
- if (parent != null && parent.getDocStringExpression() == null) {
- registerProblem(expression, "Docstring seems to be misplaced",
- new StatementEffectDocstringQuickFix());
- return true;
- }
- }
- return false;
- }
-
private boolean hasEffect(@Nullable PyExpression expression) {
if (expression == null) {
return false;
@@ -106,10 +94,6 @@
if (expression instanceof PyCallExpression || expression instanceof PyYieldExpression) {
return true;
}
-
- if (expression instanceof PyStringLiteralExpression) {
- if (DocStringUtil.isDocStringExpression(expression)) return true;
- }
else if (expression instanceof PyListCompExpression) {
if (hasEffect(((PyListCompExpression)expression).getResultExpression())) {
return true;
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectDocstringQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectDocstringQuickFix.java
deleted file mode 100644
index fa944a9..0000000
--- a/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectDocstringQuickFix.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.inspections.quickfix;
-
-import com.intellij.codeInspection.LocalQuickFix;
-import com.intellij.codeInspection.ProblemDescriptor;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.util.PsiTreeUtil;
-import com.jetbrains.python.PyBundle;
-import com.jetbrains.python.psi.*;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * User: catherine
- *
- * QuickFix to move misplaced docstring
- */
-public class StatementEffectDocstringQuickFix implements LocalQuickFix {
- @NotNull
- public String getName() {
- return PyBundle.message("QFIX.statement.effect.move.docstring");
- }
-
- @NotNull
- public String getFamilyName() {
- return getName();
- }
-
- public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
- PsiElement expression = descriptor.getPsiElement();
- if (expression instanceof PyStringLiteralExpression) {
- PyStatement st = PsiTreeUtil.getParentOfType(expression, PyStatement.class);
- if (st != null) {
- PyDocStringOwner parent = PsiTreeUtil.getParentOfType(expression, PyDocStringOwner.class);
-
- if (parent instanceof PyClass || parent instanceof PyFunction) {
- PyStatementList statementList = PsiTreeUtil.findChildOfType(parent, PyStatementList.class);
- if (statementList != null) {
- PyStatement[] statements = statementList.getStatements();
- if (statements.length > 0) {
- statementList.addBefore(st, statements[0]);
- st.delete();
- }
- }
- }
- }
- }
- }
-
-}
diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
index 3118157..82a5fd9 100644
--- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
+++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
@@ -50,7 +50,7 @@
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.remotesdk.RemoteFile;
-import com.intellij.remotesdk.RemoteSdkData;
+import com.intellij.remotesdk.RemoteSdkCredentials;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.SystemProperties;
@@ -752,10 +752,10 @@
private String getHelperPath(String helper) {
String helperPath;
final SdkAdditionalData sdkData = mySdk.getSdkAdditionalData();
- if (sdkData instanceof RemoteSdkData) {
- final RemoteSdkData remoteSdkData = (RemoteSdkData)sdkData;
- if (!StringUtil.isEmpty(remoteSdkData.getHelpersPath())) {
- helperPath = new RemoteFile(remoteSdkData.getHelpersPath(),
+ if (sdkData instanceof RemoteSdkCredentials) {
+ final RemoteSdkCredentials remoteSdkCredentials = (RemoteSdkCredentials)sdkData;
+ if (!StringUtil.isEmpty(remoteSdkCredentials.getHelpersPath())) {
+ helperPath = new RemoteFile(remoteSdkCredentials.getHelpersPath(),
helper).getPath();
}
else {
@@ -778,8 +778,8 @@
if (homePath == null) {
throw new PyExternalProcessException(ERROR_INVALID_SDK, helperPath, args, "Cannot find interpreter for SDK");
}
- if (sdkData instanceof RemoteSdkData) { //remote interpreter
- final RemoteSdkData remoteSdkData = (RemoteSdkData)sdkData;
+ if (sdkData instanceof RemoteSdkCredentials) { //remote interpreter
+ final RemoteSdkCredentials remoteSdkCredentials = (RemoteSdkCredentials)sdkData;
final PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
if (manager != null) {
final List<String> cmdline = new ArrayList<String>();
@@ -793,11 +793,11 @@
}));
try {
if (askForSudo) {
- askForSudo = !manager.ensureCanWrite(null, remoteSdkData, remoteSdkData.getInterpreterPath());
+ askForSudo = !manager.ensureCanWrite(null, remoteSdkCredentials, remoteSdkCredentials.getInterpreterPath());
}
ProcessOutput processOutput;
do {
- processOutput = manager.runRemoteProcess(null, remoteSdkData, ArrayUtil.toStringArray(cmdline), workingDir, askForSudo);
+ processOutput = manager.runRemoteProcess(null, remoteSdkCredentials, ArrayUtil.toStringArray(cmdline), workingDir, askForSudo);
if (askForSudo && processOutput.getStderr().contains("sudo: 3 incorrect password attempts")) {
continue;
}
diff --git a/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java b/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java
index 3f30b1d..d894786 100644
--- a/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java
+++ b/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java
@@ -34,6 +34,7 @@
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import org.jetbrains.annotations.NotNull;
+import java.awt.*;
import java.util.List;
import java.util.Set;
@@ -50,6 +51,7 @@
public PyInstalledPackagesPanel(Project project, PackagesNotificationPanel area) {
super(project, area);
+ setPreferredSize(new Dimension(500, 500));
myNotificationArea.addLinkHandler(INSTALL_SETUPTOOLS, new Runnable() {
@Override
diff --git a/python/src/com/jetbrains/python/parsing/FunctionParsing.java b/python/src/com/jetbrains/python/parsing/FunctionParsing.java
index cd61f6e..3fb67a8 100644
--- a/python/src/com/jetbrains/python/parsing/FunctionParsing.java
+++ b/python/src/com/jetbrains/python/parsing/FunctionParsing.java
@@ -45,7 +45,7 @@
protected void parseFunctionInnards(PsiBuilder.Marker functionMarker) {
myBuilder.advanceLexer();
- checkMatchesOrSkip(PyTokenTypes.IDENTIFIER, message("PARSE.expected.func.name"));
+ parseIdentifierOrSkip();
parseParameterList();
parseReturnTypeAnnotation();
checkMatches(PyTokenTypes.COLON, message("PARSE.expected.colon"));
diff --git a/python/src/com/jetbrains/python/parsing/Parsing.java b/python/src/com/jetbrains/python/parsing/Parsing.java
index 99eab6f..5550589 100644
--- a/python/src/com/jetbrains/python/parsing/Parsing.java
+++ b/python/src/com/jetbrains/python/parsing/Parsing.java
@@ -18,7 +18,9 @@
import com.intellij.lang.PsiBuilder;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.tree.IElementType;
+import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyElementTypes;
+import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.PyElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -61,15 +63,19 @@
return false;
}
- protected boolean checkMatchesOrSkip(final IElementType token, final String message) {
- if (myBuilder.getTokenType() == token) {
+ protected boolean parseIdentifierOrSkip() {
+ if (myBuilder.getTokenType() == PyTokenTypes.IDENTIFIER) {
myBuilder.advanceLexer();
return true;
}
- PsiBuilder.Marker mark = myBuilder.mark();
- myBuilder.advanceLexer();
- mark.error(message);
- return false;
+ else {
+ final PsiBuilder.Marker nameExpected = myBuilder.mark();
+ if (myBuilder.getTokenType() != PyTokenTypes.STATEMENT_BREAK) {
+ myBuilder.advanceLexer();
+ }
+ nameExpected.error(PyBundle.message("PARSE.expected.identifier"));
+ return false;
+ }
}
protected void assertCurrentToken(final PyElementType tokenType) {
@@ -95,7 +101,7 @@
protected boolean matchToken(final IElementType tokenType) {
if (myBuilder.getTokenType() == tokenType) {
myBuilder.advanceLexer();
- return true;
+ return true;
}
return false;
}
diff --git a/python/src/com/jetbrains/python/parsing/StatementParsing.java b/python/src/com/jetbrains/python/parsing/StatementParsing.java
index 655fadc..9c5a9d8 100644
--- a/python/src/com/jetbrains/python/parsing/StatementParsing.java
+++ b/python/src/com/jetbrains/python/parsing/StatementParsing.java
@@ -631,6 +631,10 @@
myBuilder.advanceLexer();
return true;
}
+ else if (myBuilder.getTokenType() == PyTokenTypes.STATEMENT_BREAK) {
+ myBuilder.error("Colon expected");
+ return true;
+ }
final PsiBuilder.Marker marker = myBuilder.mark();
while (!atAnyOfTokens(null, PyTokenTypes.DEDENT, PyTokenTypes.STATEMENT_BREAK, PyTokenTypes.COLON)) {
myBuilder.advanceLexer();
@@ -788,7 +792,7 @@
public void parseClassDeclaration(PsiBuilder.Marker classMarker, ParsingScope scope) {
assertCurrentToken(PyTokenTypes.CLASS_KEYWORD);
myBuilder.advanceLexer();
- checkMatchesOrSkip(PyTokenTypes.IDENTIFIER, IDENTIFIER_EXPECTED);
+ parseIdentifierOrSkip();
if (myBuilder.getTokenType() == PyTokenTypes.LPAR) {
getExpressionParser().parseArgumentList();
}
@@ -809,10 +813,8 @@
myBuilder.advanceLexer();
final PsiBuilder.Marker marker = myBuilder.mark();
- if (myBuilder.getTokenType() != PyTokenTypes.INDENT) {
- myBuilder.error("Indent expected");
- }
- else {
+ final boolean indentFound = myBuilder.getTokenType() == PyTokenTypes.INDENT;
+ if (indentFound) {
myBuilder.advanceLexer();
if (myBuilder.eof()) {
myBuilder.error("Indented block expected");
@@ -823,13 +825,16 @@
}
}
}
+ else {
+ myBuilder.error("Indent expected");
+ }
marker.done(PyElementTypes.STATEMENT_LIST);
marker.setCustomEdgeTokenBinders(LeadingCommentsBinder.INSTANCE, FollowingCommentBinder.INSTANCE);
if (endMarker != null) {
endMarker.done(elType);
}
- if (!myBuilder.eof()) {
+ if (indentFound && !myBuilder.eof()) {
checkMatches(PyTokenTypes.DEDENT, "Dedent expected");
}
// NOTE: the following line advances the PsiBuilder lexer and thus
diff --git a/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java b/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java
index ae923ed..cb9e257 100644
--- a/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java
+++ b/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.sdk.PythonSdkType;
+import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
@@ -41,8 +42,9 @@
* @author yole
*/
public class PyTreeStructureProvider implements SelectableTreeStructureProvider, DumbAware {
+ @NotNull
@Override
- public Collection<AbstractTreeNode> modify(AbstractTreeNode parent, Collection<AbstractTreeNode> children, ViewSettings settings) {
+ public Collection<AbstractTreeNode> modify(@NotNull AbstractTreeNode parent, @NotNull Collection<AbstractTreeNode> children, ViewSettings settings) {
if (parent instanceof NamedLibraryElementNode) {
return hideSkeletons((NamedLibraryElementNode)parent, children);
}
diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java
index 8af009b..83036ee 100644
--- a/python/src/com/jetbrains/python/psi/PyUtil.java
+++ b/python/src/com/jetbrains/python/psi/PyUtil.java
@@ -63,6 +63,7 @@
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import com.jetbrains.python.psi.types.*;
+import com.jetbrains.python.refactoring.classes.PyDependenciesComparator;
import com.jetbrains.python.refactoring.classes.extractSuperclass.PyExtractSuperclassHelper;
import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo;
import org.jetbrains.annotations.NonNls;
@@ -1285,6 +1286,36 @@
return instanceOf(element, toSkip) ? null : element;
}
+ /**
+ * Adds element to statement list to the correct place according to its dependencies.
+ * @param element to insert
+ * @param statementList where element should be inserted
+ * @return inserted element
+ */
+ public static <T extends PyElement>T addElementToStatementList(@NotNull final T element,
+ @NotNull final PyStatementList statementList) {
+ PsiElement before = null;
+ PsiElement after = null;
+ for (final PyStatement statement : statementList.getStatements()) {
+ if (PyDependenciesComparator.depends(element, statement)) {
+ after = statement;
+ }else if (PyDependenciesComparator.depends(statement, element)) {
+ before = statement;
+ }
+ }
+ final PsiElement result;
+ if (after != null) {
+
+ result = statementList.addAfter(element, after);
+ }else if (before != null) {
+ result = statementList.addBefore(element, before);
+ } else {
+ result = addElementToStatementList(element, statementList, true);
+ }
+ @SuppressWarnings("unchecked") // Inserted element can't have different type
+ final T resultCasted = (T)result;
+ return resultCasted;
+ }
public static PsiElement addElementToStatementList(@NotNull PsiElement element,
@NotNull PyStatementList statementList,
diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
index afca292..bea0e10 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
@@ -1172,13 +1172,13 @@
@Nullable
@Override
- public PyClassLikeType getMetaClassType(@NotNull TypeEvalContext context) {
+ public PyType getMetaClassType(@NotNull TypeEvalContext context) {
if (context.maySwitchToAST(this)) {
final PyExpression expression = getMetaClassExpression();
if (expression != null) {
final PyType type = context.getType(expression);
- if (type instanceof PyClassLikeType) {
- return (PyClassLikeType)type;
+ if (type != null) {
+ return type;
}
}
}
@@ -1193,6 +1193,17 @@
}
}
}
+ final LanguageLevel level = LanguageLevel.forElement(this);
+ if (level.isOlderThan(LanguageLevel.PYTHON30)) {
+ final PsiFile file = getContainingFile();
+ if (file instanceof PyFile) {
+ final PyFile pyFile = (PyFile)file;
+ final PsiElement element = pyFile.getElementNamed(PyNames.DUNDER_METACLASS);
+ if (element instanceof PyTypedElement) {
+ return context.getType((PyTypedElement)element);
+ }
+ }
+ }
return null;
}
@@ -1216,14 +1227,6 @@
if (attribute != null) {
return attribute;
}
- final PsiFile file = getContainingFile();
- if (file instanceof PyFile) {
- final PyFile pyFile = (PyFile)file;
- final PsiElement element = pyFile.getElementNamed(PyNames.DUNDER_METACLASS);
- if (element instanceof PyExpression) {
- return (PyExpression)element;
- }
- }
}
return null;
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java
index 1fa4b21..c1aa84c 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java
@@ -16,15 +16,19 @@
package com.jetbrains.python.psi.impl;
import com.intellij.extapi.psi.PsiFileBase;
+import com.intellij.icons.AllIcons;
import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
+import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.stubs.StubElement;
-import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.psi.util.QualifiedName;
@@ -33,11 +37,15 @@
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.indexing.IndexingDataKeys;
-import com.jetbrains.python.*;
+import com.jetbrains.python.PyElementTypes;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.PythonFileType;
+import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
import com.jetbrains.python.documentation.DocStringUtil;
import com.jetbrains.python.inspections.PythonVisitorFilter;
import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import com.jetbrains.python.psi.resolve.ResolveImportUtil;
import com.jetbrains.python.psi.resolve.VariantsProcessor;
@@ -49,6 +57,7 @@
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
+import java.io.File;
import java.util.*;
public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression {
@@ -770,4 +779,78 @@
}
return elementType == PyElementTypes.IMPORT_STATEMENT || elementType == PyElementTypes.FROM_IMPORT_STATEMENT;
}
+
+ @Override
+ public ItemPresentation getPresentation() {
+ return new ItemPresentation() {
+ @Override
+ public String getPresentableText() {
+ return getModuleName(PyFileImpl.this);
+ }
+
+ @Override
+ public String getLocationString() {
+ final String name = getLocationName();
+ return name != null ? "(" + name + ")" : null;
+ }
+
+ @Override
+ public Icon getIcon(final boolean open) {
+ if (PyUtil.isPackage(PyFileImpl.this)) {
+ return AllIcons.Modules.SourceFolder;
+ }
+ return PyFileImpl.this.getIcon(0);
+ }
+
+ @NotNull
+ private String getModuleName(@NotNull PyFile file) {
+ if (PyUtil.isPackage(file)) {
+ final PsiDirectory dir = file.getContainingDirectory();
+ if (dir != null) {
+ return dir.getName();
+ }
+ }
+ return FileUtil.getNameWithoutExtension(file.getName());
+ }
+
+ @Nullable
+ private String getLocationName() {
+ final QualifiedName name = QualifiedNameFinder.findShortestImportableQName(PyFileImpl.this);
+ if (name != null) {
+ final QualifiedName prefix = name.removeTail(1);
+ if (prefix.getComponentCount() > 0) {
+ return prefix.toString();
+ }
+ }
+ final String relativePath = getRelativeContainerPath();
+ if (relativePath != null) {
+ return relativePath;
+ }
+ final PsiDirectory psiDirectory = getParent();
+ if (psiDirectory != null) {
+ return psiDirectory.getVirtualFile().getPresentableUrl();
+ }
+ return null;
+ }
+
+ @Nullable
+ private String getRelativeContainerPath() {
+ final PsiDirectory psiDirectory = getParent();
+ if (psiDirectory != null) {
+ final VirtualFile virtualFile = getVirtualFile();
+ if (virtualFile != null) {
+ final VirtualFile root = ProjectFileIndex.SERVICE.getInstance(getProject()).getContentRootForFile(virtualFile);
+ if (root != null) {
+ final VirtualFile parent = virtualFile.getParent();
+ final VirtualFile rootParent = root.getParent();
+ if (rootParent != null && parent != null) {
+ return VfsUtilCore.getRelativePath(parent, rootParent, File.separatorChar);
+ }
+ }
+ }
+ }
+ return null;
+ }
+ };
+ }
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyKeywordArgumentManipulator.java b/python/src/com/jetbrains/python/psi/impl/PyKeywordArgumentManipulator.java
index fb4538e..5b56518 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyKeywordArgumentManipulator.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyKeywordArgumentManipulator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,13 +23,14 @@
import com.jetbrains.python.psi.PyCallExpression;
import com.jetbrains.python.psi.PyElementGenerator;
import com.jetbrains.python.psi.PyKeywordArgument;
+import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public class PyKeywordArgumentManipulator extends AbstractElementManipulator<PyKeywordArgument> {
@Override
- public PyKeywordArgument handleContentChange(PyKeywordArgument element, TextRange range, String newContent) throws IncorrectOperationException {
+ public PyKeywordArgument handleContentChange(@NotNull PyKeywordArgument element, @NotNull TextRange range, String newContent) throws IncorrectOperationException {
final ASTNode keywordNode = element.getKeywordNode();
if (keywordNode != null && keywordNode.getTextRange().shiftRight(-element.getTextRange().getStartOffset()).equals(range)) {
final LanguageLevel langLevel = LanguageLevel.forElement(element);
diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionManipulator.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionManipulator.java
index 5ea4583..9e20ba5 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionManipulator.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionManipulator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,18 +20,21 @@
import com.intellij.psi.AbstractElementManipulator;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.psi.PyReferenceExpression;
+import org.jetbrains.annotations.NotNull;
/**
* @author oleg
*/
public class PyReferenceExpressionManipulator extends AbstractElementManipulator<PyReferenceExpression> {
- public PyReferenceExpression handleContentChange(final PyReferenceExpression element, final TextRange range, final String newContent)
+ @Override
+ public PyReferenceExpression handleContentChange(@NotNull final PyReferenceExpression element, @NotNull final TextRange range, final String newContent)
throws IncorrectOperationException {
return null;
}
+ @NotNull
@Override
- public TextRange getRangeInElement(final PyReferenceExpression element) {
+ public TextRange getRangeInElement(@NotNull final PyReferenceExpression element) {
final ASTNode nameElement = element.getNameElement();
final int startOffset = nameElement != null ? nameElement.getStartOffset() : element.getTextRange().getEndOffset();
return new TextRange(startOffset - element.getTextOffset(), element.getTextLength());
diff --git a/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionManipulator.java b/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionManipulator.java
index f98acde..5032d12 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionManipulator.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionManipulator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,13 +20,15 @@
import com.intellij.psi.AbstractElementManipulator;
import com.jetbrains.python.PythonStringUtil;
import com.jetbrains.python.psi.PyElementGenerator;
+import org.jetbrains.annotations.NotNull;
/**
* @author traff
*/
public class PyStringLiteralExpressionManipulator extends AbstractElementManipulator<PyStringLiteralExpressionImpl> {
- public PyStringLiteralExpressionImpl handleContentChange(PyStringLiteralExpressionImpl element, TextRange range, String newContent) {
+ @Override
+ public PyStringLiteralExpressionImpl handleContentChange(@NotNull PyStringLiteralExpressionImpl element, @NotNull TextRange range, String newContent) {
Pair<String, String> quotes = PythonStringUtil.getQuotes(range.substring(element.getText()));
if (quotes != null) {
@@ -39,8 +41,9 @@
.replace(PyElementGenerator.getInstance(element.getProject()).createStringLiteralAlreadyEscaped(newName));
}
+ @NotNull
@Override
- public TextRange getRangeInElement(PyStringLiteralExpressionImpl element) {
+ public TextRange getRangeInElement(@NotNull PyStringLiteralExpressionImpl element) {
Pair<String, String> pair = PythonStringUtil.getQuotes(element.getText());
if (pair != null) {
return TextRange.from(pair.first.length(), element.getTextLength() - pair.first.length() - pair.second.length());
diff --git a/python/src/com/jetbrains/python/psi/resolve/PythonPathCache.java b/python/src/com/jetbrains/python/psi/resolve/PythonPathCache.java
index 28413c3..d2c0aa6 100644
--- a/python/src/com/jetbrains/python/psi/resolve/PythonPathCache.java
+++ b/python/src/com/jetbrains/python/psi/resolve/PythonPathCache.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
import com.intellij.openapi.vfs.*;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.QualifiedName;
+import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.List;
@@ -53,27 +54,27 @@
protected class MyVirtualFileAdapter extends VirtualFileAdapter {
@Override
- public void fileCreated(VirtualFileEvent event) {
+ public void fileCreated(@NotNull VirtualFileEvent event) {
clearCache();
}
@Override
- public void fileDeleted(VirtualFileEvent event) {
+ public void fileDeleted(@NotNull VirtualFileEvent event) {
clearCache();
}
@Override
- public void fileMoved(VirtualFileMoveEvent event) {
+ public void fileMoved(@NotNull VirtualFileMoveEvent event) {
clearCache();
}
@Override
- public void fileCopied(VirtualFileCopyEvent event) {
+ public void fileCopied(@NotNull VirtualFileCopyEvent event) {
clearCache();
}
@Override
- public void propertyChanged(VirtualFilePropertyEvent event) {
+ public void propertyChanged(@NotNull VirtualFilePropertyEvent event) {
if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) {
clearCache();
}
diff --git a/python/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java b/python/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java
new file mode 100644
index 0000000..105aec5
--- /dev/null
+++ b/python/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.psi.stubs;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.indexing.*;
+import com.intellij.util.io.EnumeratorStringDescriptor;
+import com.intellij.util.io.KeyDescriptor;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.PythonFileType;
+import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.search.PyProjectScopeBuilder;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
+/**
+ * @author vlan
+ */
+public class PyModuleNameIndex extends ScalarIndexExtension<String> {
+ public static final ID<String, Void> NAME = ID.create("Py.module.name");
+
+ private final EnumeratorStringDescriptor myKeyDescriptor = new EnumeratorStringDescriptor();
+ private final DataIndexer<String, Void, FileContent> myDataIndexer = new DataIndexer<String, Void, FileContent>() {
+ @NotNull
+ @Override
+ public Map<String, Void> map(FileContent inputData) {
+ final VirtualFile file = inputData.getFile();
+ final String name = file.getName();
+ if (PyNames.INIT_DOT_PY.equals(name)) {
+ final VirtualFile parent = file.getParent();
+ if (parent != null && parent.isDirectory()) {
+ return Collections.singletonMap(parent.getName(), null);
+ }
+ }
+ else {
+ return Collections.singletonMap(FileUtil.getNameWithoutExtension(name), null);
+ }
+ return Collections.emptyMap();
+ }
+ };
+
+ @NotNull
+ @Override
+ public ID<String, Void> getName() {
+ return NAME;
+ }
+
+ @NotNull
+ @Override
+ public DataIndexer<String, Void, FileContent> getIndexer() {
+ return myDataIndexer;
+ }
+
+ @Override
+ public KeyDescriptor<String> getKeyDescriptor() {
+ return myKeyDescriptor;
+ }
+
+ @Override
+ public FileBasedIndex.InputFilter getInputFilter() {
+ return new DefaultFileTypeSpecificInputFilter(PythonFileType.INSTANCE);
+ }
+
+ @Override
+ public boolean dependsOnFileContent() {
+ return true;
+ }
+
+ @Override
+ public int getVersion() {
+ return 0;
+ }
+
+ @NotNull
+ public static Collection<String> getAllKeys(@NotNull Project project) {
+ return FileBasedIndex.getInstance().getAllKeys(NAME, project);
+ }
+
+ @NotNull
+ public static List<PyFile> find(@NotNull String name, @NotNull Project project, boolean includeNonProjectItems) {
+ final List<PyFile> results = new ArrayList<PyFile>();
+ final GlobalSearchScope scope = includeNonProjectItems
+ ? PyProjectScopeBuilder.excludeSdkTestsScope(project)
+ : GlobalSearchScope.projectScope(project);
+ final Collection<VirtualFile> files = FileBasedIndex.getInstance().getContainingFiles(NAME, name, scope);
+ for (VirtualFile virtualFile : files) {
+ final PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
+ if (psiFile instanceof PyFile) {
+ results.add((PyFile)psiFile);
+ }
+ }
+ return results;
+ }
+}
diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java
index 10c06f5..715421a 100644
--- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java
+++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java
@@ -267,9 +267,9 @@
@Nullable
@Override
public PyClassLikeType getMetaClassType(@NotNull TypeEvalContext context, boolean inherited) {
- final PyClassLikeType ownMeta = myClass.getMetaClassType(context);
+ final PyType ownMeta = myClass.getMetaClassType(context);
if (ownMeta != null) {
- return ownMeta;
+ return (ownMeta instanceof PyClassLikeType) ? (PyClassLikeType)ownMeta : null;
}
if (inherited) {
for (PyClassLikeType ancestor : myClass.getAncestorTypes(context)) {
diff --git a/python/src/com/jetbrains/python/refactoring/classes/DependencyVisitor.java b/python/src/com/jetbrains/python/refactoring/classes/DependencyVisitor.java
new file mode 100644
index 0000000..b22449d
--- /dev/null
+++ b/python/src/com/jetbrains/python/refactoring/classes/DependencyVisitor.java
@@ -0,0 +1,87 @@
+package com.jetbrains.python.refactoring.classes;
+
+import com.intellij.openapi.util.Condition;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiPolyVariantReference;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.python.psi.*;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Searches for element in another element's usages.
+ * Parametrize it with needle and make stack to accept it.
+ *
+ * @author Ilya.Kazakevich
+ */
+class DependencyVisitor extends PyRecursiveElementVisitor {
+
+ @NotNull
+ private final PyElement myElementToFind;
+ private boolean myDependencyFound;
+
+ /**
+ * @param elementToFind what to find
+ */
+ DependencyVisitor(@NotNull final PyElement elementToFind) {
+ myElementToFind = elementToFind;
+ }
+
+ @Override
+ public void visitPyCallExpression(@NotNull final PyCallExpression node) {
+ final PyExpression callee = node.getCallee();
+ if (callee != null) {
+ final PsiReference calleeReference = callee.getReference();
+ if ((calleeReference != null) && calleeReference.isReferenceTo(myElementToFind)) {
+ myDependencyFound = true;
+ return;
+ }
+ final String calleeName = callee.getName();
+
+ if ((calleeName != null) && calleeName.equals(myElementToFind.getName())) { // Check by name also
+ myDependencyFound = true;
+ }
+ }
+ }
+
+ @Override
+ public void visitPyReferenceExpression(final PyReferenceExpression node) {
+
+ final PsiPolyVariantReference reference = node.getReference();
+ if (reference.isReferenceTo(myElementToFind)) {
+ myDependencyFound = true;
+ return;
+ }
+ // TODO: This step is member-type specific. Move to MemberManagers?
+ if (myElementToFind instanceof PyAssignmentStatement) {
+ final PyExpression[] targets = ((PyAssignmentStatement)myElementToFind).getTargets();
+
+ if (targets.length != 1) {
+ return;
+ }
+ final PyExpression expression = targets[0];
+
+ if (reference.isReferenceTo(expression)) {
+ myDependencyFound = true;
+ return;
+ }
+ if (node.getText().equals(expression.getText())) { // Check by name also
+ myDependencyFound = true;
+ }
+ return;
+ }
+ final PsiElement declaration = reference.resolve();
+ myDependencyFound = PsiTreeUtil.findFirstParent(declaration, new PsiElementCondition()) != null;
+ }
+
+ public boolean isDependencyFound() {
+ return myDependencyFound;
+ }
+
+ private class PsiElementCondition implements Condition<PsiElement> {
+ @Override
+ public boolean value(final PsiElement psiElement) {
+ return psiElement.equals(myElementToFind);
+ }
+ }
+}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java b/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java
index 1033661..79f0382 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java
@@ -60,19 +60,68 @@
/**
* Copies class field declarations to some other place
*
- * @param assignmentStatement list of class fields
+ * @param assignmentStatements list of class fields
+ * @param dequalifyIfDeclaredInClass If not null method will check if field declared in this class.
+ * If declared -- qualifier will be removed.
+ * For example: MyClass.Foo will become Foo it this param is MyClass.
* @return new (copied) fields
*/
@NotNull
- public static List<PyAssignmentStatement> copyFieldDeclarationToStatement(@NotNull final Collection<PyAssignmentStatement> assignmentStatement,
- @NotNull final PyStatementList superClassStatement) {
- final List<PyAssignmentStatement> declations = new ArrayList<PyAssignmentStatement>(assignmentStatement.size());
- for (final PyAssignmentStatement expression : assignmentStatement) {
- final PyAssignmentStatement newDeclaration = (PyAssignmentStatement)expression.copy();
- declations.add((PyAssignmentStatement)PyUtil.addElementToStatementList(newDeclaration, superClassStatement, true));
+ public static List<PyAssignmentStatement> copyFieldDeclarationToStatement(@NotNull final Collection<PyAssignmentStatement> assignmentStatements,
+ @NotNull final PyStatementList superClassStatement,
+ @Nullable final PyClass dequalifyIfDeclaredInClass) {
+ final List<PyAssignmentStatement> declarations = new ArrayList<PyAssignmentStatement>(assignmentStatements.size());
+ Collections.sort(declarations, PyDependenciesComparator.INSTANCE);
+
+
+ for (final PyAssignmentStatement pyAssignmentStatement : assignmentStatements) {
+ final PyElement value = pyAssignmentStatement.getAssignedValue();
+ final PyAssignmentStatement newDeclaration = (PyAssignmentStatement)pyAssignmentStatement.copy();
+
+ if (value instanceof PyReferenceExpression && dequalifyIfDeclaredInClass != null) {
+ final String newValue = getNewValueToAssign((PyReferenceExpression)value, dequalifyIfDeclaredInClass);
+
+ setNewAssigneeValue(newDeclaration, newValue);
+
+ }
+
+ declarations.add(PyUtil.addElementToStatementList(newDeclaration, superClassStatement));
PyPsiUtils.removeRedundantPass(superClassStatement);
}
- return declations;
+ return declarations;
+ }
+
+ /**
+ * Sets new value to assignment statement.
+ * @param assignmentStatement statement to change
+ * @param newValue new value
+ */
+ private static void setNewAssigneeValue(@NotNull final PyAssignmentStatement assignmentStatement, @NotNull final String newValue) {
+ final PyExpression oldValue = assignmentStatement.getAssignedValue();
+ final PyExpression newExpression =
+ PyElementGenerator.getInstance(assignmentStatement.getProject()).createExpressionFromText(LanguageLevel.forElement(assignmentStatement), newValue);
+ if (oldValue != null) {
+ oldValue.replace(newExpression);
+ } else {
+ assignmentStatement.add(newExpression);
+ }
+ }
+
+ /**
+ * Checks if current value declared in provided class and removes class qualifier if true
+ * @param currentValue current value
+ * @param dequalifyIfDeclaredInClass class to check
+ * @return value as string
+ */
+ @NotNull
+ private static String getNewValueToAssign(@NotNull final PyReferenceExpression currentValue, @NotNull final PyClass dequalifyIfDeclaredInClass) {
+ final PyExpression qualifier = currentValue.getQualifier();
+ if ((qualifier instanceof PyReferenceExpression) &&
+ ((PyReferenceExpression)qualifier).getReference().isReferenceTo(dequalifyIfDeclaredInClass)) {
+ final String name = currentValue.getName();
+ return ((name != null) ? name : currentValue.getText());
+ }
+ return currentValue.getText();
}
@NotNull
@@ -80,11 +129,11 @@
if (methods.isEmpty()) {
return Collections.emptyList();
}
- for (PsiElement e : methods) {
+ for (final PsiElement e : methods) {
rememberNamedReferences(e);
}
final PyFunction[] elements = methods.toArray(new PyFunction[methods.size()]);
- return addMethods(superClass, elements);
+ return addMethods(superClass, true, elements);
}
/**
@@ -92,28 +141,31 @@
*
* @param destination where to add methods
* @param methods methods
- * @return newly added methods
+ * @param skipIfExist do not add anything if method already exists
+ * @return newly added methods or existing one (if skipIfExists is true and method already exists)
*/
@NotNull
- public static List<PyFunction> addMethods(@NotNull final PyClass destination, @NotNull final PyFunction... methods) {
+ public static List<PyFunction> addMethods(@NotNull final PyClass destination, final boolean skipIfExist, @NotNull final PyFunction... methods) {
final PyStatementList destStatementList = destination.getStatementList();
- final List<PyFunction> newlyCreatedMethods = new ArrayList<PyFunction>(methods.length);
+ final List<PyFunction> result = new ArrayList<PyFunction>(methods.length);
for (final PyFunction method : methods) {
- if (destination.findMethodByName(method.getName(), false) != null) {
- continue; //We skip adding if class already has this method. I am not sure if this behaviour is correct, but it was here, so I left if for backward compatibility
+ final PyFunction existingMethod = destination.findMethodByName(method.getName(), false);
+ if ((existingMethod != null) && skipIfExist) {
+ result.add(existingMethod);
+ continue; //We skip adding if class already has this method.
}
final PyFunction newMethod = insertMethodInProperPlace(destStatementList, method);
- newlyCreatedMethods.add(newMethod);
+ result.add(newMethod);
restoreNamedReferences(newMethod);
}
PyPsiUtils.removeRedundantPass(destStatementList);
- return newlyCreatedMethods;
+ return result;
}
/**
diff --git a/python/src/com/jetbrains/python/refactoring/classes/PyDependenciesComparator.java b/python/src/com/jetbrains/python/refactoring/classes/PyDependenciesComparator.java
new file mode 100644
index 0000000..700a300
--- /dev/null
+++ b/python/src/com/jetbrains/python/refactoring/classes/PyDependenciesComparator.java
@@ -0,0 +1,70 @@
+package com.jetbrains.python.refactoring.classes;
+
+import com.jetbrains.python.psi.*;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * Compares elements by their dependencies.
+ * If A depends on B, then A < B
+ */
+public class PyDependenciesComparator implements Comparator<PyElement>, Serializable {
+
+ /**
+ * Singleton comparator instance
+ */
+ public static final PyDependenciesComparator INSTANCE = new PyDependenciesComparator();
+
+ private PyDependenciesComparator() {
+ }
+
+ @Override
+ public int compare(@NotNull final PyElement o1, @NotNull final PyElement o2) {
+ if (depends(o1, o2)) {
+ return 1;
+ }
+ if (depends(o2, o1)) {
+ return -1;
+ }
+ return getBlockType(o1).compareTo(getBlockType(o2));
+ }
+
+ @NotNull
+ private static BlockType getBlockType(@NotNull final PyElement statement) {
+ for (BlockType type : BlockType.values()) {
+ if (type.myClass.isAssignableFrom(statement.getClass())) {
+ return type;
+ }
+ }
+
+ return BlockType.OTHER;
+ }
+
+ /**
+ * @return true if first param depends on second.
+ */
+ public static boolean depends(@NotNull final PyElement o1, @NotNull final PyElement o2) {
+ final DependencyVisitor visitor = new DependencyVisitor(o2);
+ o1.accept(visitor);
+ return visitor.isDependencyFound();
+ }
+
+ /**
+ * Types of class members in order, they should appear
+ */
+ private enum BlockType {
+ DOC(PyExpressionStatement.class),
+ DECLARATION(PyAssignmentStatement.class),
+ METHOD(PyFunction.class),
+ OTHER(PyElement.class);
+
+ @NotNull
+ private final Class<? extends PyElement> myClass;
+
+ BlockType(@NotNull final Class<? extends PyElement> aClass) {
+ myClass = aClass;
+ }
+ }
+}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/PyDependentMembersCollector.java b/python/src/com/jetbrains/python/refactoring/classes/PyDependentMembersCollector.java
index 5efb352..c47c474 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/PyDependentMembersCollector.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/PyDependentMembersCollector.java
@@ -17,7 +17,7 @@
import com.intellij.refactoring.classMembers.DependentMembersCollectorBase;
import com.jetbrains.python.psi.*;
-import com.jetbrains.python.psi.resolve.PyResolveContext;
+import com.jetbrains.python.refactoring.classes.membersManager.MembersManager;
/**
* @author Dennis.Ushakov
@@ -28,26 +28,7 @@
}
@Override
- public void collect(PyElement member) {
- //TODO: Move to MembersManager as well
- final PyRecursiveElementVisitor visitor = new PyRecursiveElementVisitor() {
- @Override
- public void visitPyCallExpression(PyCallExpression node) {
- final Callable markedFunction = node.resolveCalleeFunction(PyResolveContext.noImplicits());
- final PyFunction function = markedFunction != null ? markedFunction.asMethod() : null;
- if (!existsInSuperClass(function)) {
- myCollection.add(function);
- }
- }
- };
- member.accept(visitor);
- }
-
- private boolean existsInSuperClass(PyFunction classMember) {
- if (getSuperClass() == null) return false;
- final String name = classMember != null ? classMember.getName() : null;
- if (name == null) return false;
- final PyFunction methodBySignature = (getSuperClass()).findMethodByName(name, true);
- return methodBySignature != null;
+ public void collect(final PyElement member) {
+ myCollection.addAll(MembersManager.getAllDependencies(myClass, member, getSuperClass()));
}
}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassPresenterImpl.java b/python/src/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassPresenterImpl.java
index 4d2190a..87ec445 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassPresenterImpl.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassPresenterImpl.java
@@ -6,14 +6,17 @@
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
import com.intellij.refactoring.RefactoringBundle;
-import com.intellij.util.containers.MultiMap;
+import com.intellij.refactoring.classMembers.MemberInfoModel;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElement;
+import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.refactoring.classes.PyMemberInfoStorage;
import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo;
@@ -24,28 +27,20 @@
import java.io.File;
import java.io.IOException;
import java.util.Collection;
+import java.util.Collections;
/**
* @author Ilya.Kazakevich
*/
-class PyExtractSuperclassPresenterImpl extends MembersBasedPresenterNoPreviewImpl<PyExtractSuperclassView>
+class PyExtractSuperclassPresenterImpl extends MembersBasedPresenterNoPreviewImpl<PyExtractSuperclassView,
+ MemberInfoModel<PyElement, PyMemberInfo<PyElement>>>
implements PyExtractSuperclassPresenter {
private final NamesValidator myNamesValidator = LanguageNamesValidation.INSTANCE.forLanguage(PythonLanguage.getInstance());
-
- @NotNull
- private static final MultiMap<PsiElement, String> EMPTY_MAP = MultiMap.create();
-
PyExtractSuperclassPresenterImpl(@NotNull final PyExtractSuperclassView view,
@NotNull final PyClass classUnderRefactoring,
@NotNull final PyMemberInfoStorage infoStorage) {
- super(view, classUnderRefactoring, infoStorage);
- }
-
- @NotNull
- @Override
- protected MultiMap<PsiElement, String> getConflicts() {
- return EMPTY_MAP; //There are no conflicts for extracting
+ super(view, classUnderRefactoring, infoStorage, new PyExtractSuperclassInfoModel(classUnderRefactoring));
}
@Override
@@ -56,8 +51,9 @@
throw new BadDataException(PyBundle.message("refactoring.extract.super.name.0.must.be.ident", myView.getSuperClassName()));
}
boolean rootFound = false;
+ final File moduleFile = new File(myView.getModuleFile());
try {
- final String targetDir = FileUtil.toSystemIndependentName(new File(myView.getModuleFile()).getCanonicalPath());
+ final String targetDir = FileUtil.toSystemIndependentName(moduleFile.getCanonicalPath());
for (final VirtualFile file : ProjectRootManager.getInstance(project).getContentRoots()) {
if (StringUtil.startsWithIgnoreCase(targetDir, file.getPath())) {
rootFound = true;
@@ -70,6 +66,19 @@
if (!rootFound) {
throw new BadDataException(PyBundle.message("refactoring.extract.super.target.path.outside.roots"));
}
+
+ // TODO: Cover with test. It can't be done for now, because testFixture reports root path incorrectly
+ // PY-12173
+ myView.getModuleFile();
+ final VirtualFile moduleVirtualFile = LocalFileSystem.getInstance().findFileByIoFile(moduleFile);
+ if (moduleVirtualFile != null) {
+ final PsiFile psiFile = PsiManager.getInstance(project).findFile(moduleVirtualFile);
+ if (psiFile instanceof PyFile) {
+ if (((PyFile)psiFile).findTopLevelClass(myView.getSuperClassName()) != null) {
+ throw new BadDataException(PyBundle.message("refactoring.extract.super.target.class.already.exists", myView.getSuperClassName()));
+ }
+ }
+ }
}
@Override
@@ -79,10 +88,10 @@
final Collection<PyMemberInfo<PyElement>> pyMemberInfos =
PyUtil.filterOutObject(myStorage.getClassMemberInfos(myClassUnderRefactoring));
myView.configure(
- new PyExtractSuperclassInitializationInfo(new PyExtractSuperclassInfoModel(myClassUnderRefactoring), pyMemberInfos, defaultFilePath,
- roots));
+ new PyExtractSuperclassInitializationInfo(myModel, pyMemberInfos, defaultFilePath,
+ roots)
+ );
myView.initAndShow();
-
}
@NotNull
@@ -96,4 +105,10 @@
PyExtractSuperclassHelper
.extractSuperclass(myClassUnderRefactoring, myView.getSelectedMemberInfos(), myView.getSuperClassName(), myView.getModuleFile());
}
+
+ @NotNull
+ @Override
+ protected Iterable<? extends PyClass> getDestClassesToCheckConflicts() {
+ return Collections.emptyList(); // No conflict can take place in newly created classes
+ }
}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/ClassFieldsManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/ClassFieldsManager.java
index b6faa3a..3bf4f00 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/ClassFieldsManager.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/ClassFieldsManager.java
@@ -22,15 +22,19 @@
super(true);
}
+ @Override
+ public boolean hasConflict(@NotNull final PyTargetExpression member, @NotNull final PyClass aClass) {
+ return NamePredicate.hasElementWithSameName(member, aClass.getClassAttributes());
+ }
@Override
protected Collection<PyElement> moveAssignments(@NotNull final PyClass from,
- @NotNull final Collection<PyAssignmentStatement> statements,
- @NotNull final PyClass... to) {
+ @NotNull final Collection<PyAssignmentStatement> statements,
+ @NotNull final PyClass... to) {
//TODO: Copy/paste with InstanceFieldsManager. Move to parent?
final List<PyElement> result = new ArrayList<PyElement>();
for (final PyClass destClass : to) {
- result.addAll(PyClassRefactoringUtil.copyFieldDeclarationToStatement(statements, destClass.getStatementList()));
+ result.addAll(PyClassRefactoringUtil.copyFieldDeclarationToStatement(statements, destClass.getStatementList(), destClass));
}
deleteElements(statements);
PyClassRefactoringUtil.insertPassIfNeeded(from);
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/FieldsManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/FieldsManager.java
index d27ec8e..cb15b2b 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/FieldsManager.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/FieldsManager.java
@@ -5,15 +5,14 @@
import com.google.common.collect.Lists;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.containers.MultiMap;
import com.jetbrains.NotNullPredicate;
-import com.jetbrains.python.psi.PyAssignmentStatement;
-import com.jetbrains.python.psi.PyClass;
-import com.jetbrains.python.psi.PyElement;
-import com.jetbrains.python.psi.PyTargetExpression;
+import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
/**
@@ -34,6 +33,21 @@
myStatic = isStatic;
}
+
+ @NotNull
+ @Override
+ protected Collection<PyElement> getDependencies(@NotNull final MultiMap<PyClass, PyElement> usedElements) {
+ return Collections.emptyList();
+ }
+
+ @NotNull
+ @Override
+ protected MultiMap<PyClass, PyElement> getDependencies(@NotNull final PyElement member) {
+ final MultiMap<PyClass, PyElement> result = new MultiMap<PyClass, PyElement>();
+ member.accept(new MyPyRecursiveElementVisitor(result));
+ return result;
+ }
+
@Override
protected Collection<? extends PyElement> getElementsToStoreReferences(@NotNull final Collection<PyTargetExpression> elements) {
// We need to save references from assignments
@@ -50,7 +64,8 @@
protected Collection<PyElement> moveMembers(@NotNull final PyClass from,
@NotNull final Collection<PyMemberInfo<PyTargetExpression>> members,
@NotNull final PyClass... to) {
- return moveAssignments(from, Collections2.filter(Collections2.transform(fetchElements(members), ASSIGNMENT_TRANSFORM), NotNullPredicate.INSTANCE),
+ return moveAssignments(from, Collections2
+ .filter(Collections2.transform(fetchElements(members), ASSIGNMENT_TRANSFORM), NotNullPredicate.INSTANCE),
to);
}
@@ -116,4 +131,27 @@
return PsiTreeUtil.getParentOfType(input, PyAssignmentStatement.class);
}
}
+
+ /**
+ * Fetches field declarations
+ */
+ private static class MyPyRecursiveElementVisitor extends PyRecursiveElementVisitor {
+ @NotNull
+ private final MultiMap<PyClass, PyElement> myResult;
+
+ private MyPyRecursiveElementVisitor(@NotNull final MultiMap<PyClass, PyElement> result) {
+ myResult = result;
+ }
+
+ @Override
+ public void visitPyReferenceExpression(final PyReferenceExpression node) {
+ final PsiElement declaration = node.getReference().resolve();
+ if (declaration instanceof PyElement) {
+ final PyClass parent = PsiTreeUtil.getParentOfType(declaration, PyClass.class);
+ if (parent != null) {
+ myResult.putValue(parent, (PyElement)declaration);
+ }
+ }
+ }
+ }
}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/InstanceFieldsManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/InstanceFieldsManager.java
index ba6cb0c..a1e19c4 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/InstanceFieldsManager.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/InstanceFieldsManager.java
@@ -8,6 +8,7 @@
import com.jetbrains.python.psi.impl.PyFunctionBuilder;
import com.jetbrains.python.refactoring.classes.PyClassRefactoringUtil;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
@@ -24,6 +25,10 @@
super(false);
}
+ @Override
+ public boolean hasConflict(@NotNull final PyTargetExpression member, @NotNull final PyClass aClass) {
+ return NamePredicate.hasElementWithSameName(member, aClass.getInstanceAttributes());
+ }
@Override
protected Collection<PyElement> moveAssignments(@NotNull final PyClass from,
@@ -62,7 +67,7 @@
toInitMethod = createInitMethod(to);
}
final PyStatementList statementList = toInitMethod.getStatementList();
- return PyClassRefactoringUtil.copyFieldDeclarationToStatement(members, statementList);
+ return PyClassRefactoringUtil.copyFieldDeclarationToStatement(members, statementList, null);
}
/**
@@ -77,7 +82,7 @@
final PyFunctionBuilder functionBuilder = new PyFunctionBuilder(PyNames.INIT);
functionBuilder.parameter(PyNames.CANONICAL_SELF); //TODO: Take param from codestyle?
final PyFunction function = functionBuilder.buildFunction(to.getProject(), LanguageLevel.forElement(to));
- return PyClassRefactoringUtil.addMethods(to, function).get(0);
+ return PyClassRefactoringUtil.addMethods(to, true, function).get(0);
}
@Override
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/MembersConflictDialog.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MembersConflictDialog.java
new file mode 100644
index 0000000..b288f95
--- /dev/null
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MembersConflictDialog.java
@@ -0,0 +1,62 @@
+package com.jetbrains.python.refactoring.classes.membersManager;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.refactoring.RefactoringBundle;
+import com.intellij.refactoring.ui.ConflictsDialog;
+import com.intellij.refactoring.util.RefactoringUIUtil;
+import com.intellij.util.containers.MultiMap;
+import com.jetbrains.python.PyBundle;
+import com.jetbrains.python.psi.PyClass;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+
+/**
+ * Displays error messages about fact that destination class already contains some member infos
+ * or members under refactoring would not be available at the new place.
+ *
+ * @author Ilya.Kazakevich
+ */
+public class MembersConflictDialog extends ConflictsDialog {
+ /**
+ * @param project project under refactoring
+ * @param duplicatesConflict duplicates conflicts : that means destination class has the same member.
+ * If member "foo" already exists in class "bar": pass [bar] -] [foo].
+ * @param dependenciesConflicts dependency conflict: list of elements used by member under refactoring and would not be available
+ * at new destination. If user wants to move method, that uses field "bar" which would not be available at new class,
+ * pass [bar] field
+ */
+ public MembersConflictDialog(
+ @NotNull final Project project,
+ @NotNull final MultiMap<PyClass, PyMemberInfo<?>> duplicatesConflict,
+ @NotNull final Collection<PyMemberInfo<?>> dependenciesConflicts) {
+ super(project, convertDescription(duplicatesConflict, dependenciesConflicts), null, true, false);
+ }
+
+ @NotNull
+ private static MultiMap<PsiElement, String> convertDescription(
+ @NotNull final MultiMap<PyClass, PyMemberInfo<?>> duplicateConflictDescriptions,
+ @NotNull final Collection<PyMemberInfo<?>> dependenciesConflicts) {
+ final MultiMap<PsiElement, String> result = new MultiMap<PsiElement, String>();
+ for (final PyClass aClass : duplicateConflictDescriptions.keySet()) {
+ for (final PyMemberInfo<?> pyMemberInfo : duplicateConflictDescriptions.get(aClass)) {
+ final String message = RefactoringBundle.message("0.already.contains.a.1",
+ RefactoringUIUtil.getDescription(aClass, false),
+ RefactoringUIUtil.getDescription(pyMemberInfo.getMember(), false));
+ result.putValue(aClass, message);
+ }
+ }
+
+ for (final PyMemberInfo<?> memberUnderConflict : dependenciesConflicts) {
+ result.putValue(memberUnderConflict.getMember(), PyBundle.message(
+ "refactoring.will.not.be.accessible",
+ RefactoringUIUtil.getDescription(memberUnderConflict.getMember(), false)
+ )
+ );
+ }
+
+
+ return result;
+ }
+}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/MembersManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MembersManager.java
index 6be3f9d..437b808 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/MembersManager.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MembersManager.java
@@ -18,18 +18,18 @@
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
-import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Collections2;
-import com.google.common.collect.Multimap;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.containers.MultiMap;
import com.jetbrains.NotNullPredicate;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.refactoring.classes.PyClassRefactoringUtil;
+import com.jetbrains.python.refactoring.classes.PyDependenciesComparator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.jetbrains.annotations.TestOnly;
import java.util.*;
@@ -74,6 +74,7 @@
/**
* Transforms elements, manager says it could move to appropriate {@link com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo}.
* Types are checked at runtime.
+ *
* @param pyClass class whose members we want to move
* @param manager manager that should check class and report list of memebers
* @return member infos
@@ -81,9 +82,10 @@
//TODO: Move to TypeSafeMovingStrategy
@NotNull
@SuppressWarnings({"unchecked", "rawtypes"}) //We check type at runtime
- private static Collection<PyMemberInfo<PyElement>> transformSafely(@NotNull final PyClass pyClass, @NotNull final MembersManager<?> manager) {
+ private static Collection<PyMemberInfo<PyElement>> transformSafely(@NotNull final PyClass pyClass,
+ @NotNull final MembersManager<?> manager) {
final List<PyElement> membersCouldBeMoved = manager.getMembersCouldBeMoved(pyClass);
- manager.checkElementTypes((Collection)membersCouldBeMoved);
+ manager.checkElementTypes((Iterable)membersCouldBeMoved);
return (Collection<PyMemberInfo<PyElement>>)Collections2.transform(membersCouldBeMoved, (Function)manager);
}
@@ -100,6 +102,20 @@
@NotNull final PyClass from,
@NotNull final PyClass... to
) {
+ List<PyMemberInfo<PyElement>> memberInfosSorted = new ArrayList<PyMemberInfo<PyElement>>(memberInfos);
+ Collections.sort(memberInfosSorted, new Comparator<PyMemberInfo<PyElement>>() {
+ @Override
+ public int compare(PyMemberInfo<PyElement> o1, PyMemberInfo<PyElement> o2) {
+ return PyDependenciesComparator.INSTANCE.compare(o1.getMember(), o2.getMember());
+ }
+ });
+
+ for (PyMemberInfo<PyElement> info : memberInfosSorted) {
+ TypeSafeMovingStrategy.moveCheckingTypesAtRunTime(from, info.getMembersManager(), Collections.singleton(info), to);
+ }
+
+
+ /*//Move at once, sort
final Multimap<MembersManager<PyElement>, PyMemberInfo<PyElement>> managerToMember = ArrayListMultimap.create();
//Collect map (manager)->(list_of_memebers)
for (final PyMemberInfo<PyElement> memberInfo : memberInfos) {
@@ -109,18 +125,17 @@
for (final MembersManager<PyElement> membersManager : managerToMember.keySet()) {
final Collection<PyMemberInfo<PyElement>> members = managerToMember.get(membersManager);
TypeSafeMovingStrategy.moveCheckingTypesAtRunTime(from, membersManager, members, to);
- }
+ }*/
PyClassRefactoringUtil.insertPassIfNeeded(from);
}
-
/**
* Checks that all elements has allowed type for manager
*
- * @param members elements to check against manager
+ * @param elements elements to check against manager
*/
- void checkElementTypes(@NotNull final Collection<T> elements) {
+ void checkElementTypes(@NotNull final Iterable<T> elements) {
for (final PyElement pyElement : elements) {
Preconditions.checkArgument(myExpectedClass.isAssignableFrom(pyElement.getClass()),
String.format("Manager %s expected %s but got %s", this, myExpectedClass, pyElement));
@@ -159,10 +174,11 @@
}
/**
- * Finds member in class. It is here only for backward compatibility with some tests.
+ * Finds member in class.
+ * @param pyClass class to find member in
+ * @param pyElement element to find
+ * @return member info with element
*/
- //TODO: mark deprecated?
- @TestOnly
@NotNull
public static PyMemberInfo<PyElement> findMember(@NotNull final PyClass pyClass, @NotNull final PyElement pyElement) {
final PyMemberInfo<PyElement> result = findMember(pyClass, new FindByElement(pyElement));
@@ -245,8 +261,9 @@
/**
* Fetches elements from member info.
+ *
* @param memberInfos member info to fetch elements from
- * @param <T> type of element
+ * @param <T> type of element
* @return list of elements
*/
@NotNull
@@ -254,6 +271,84 @@
return Collections2.transform(memberInfos, new PyMemberExtractor<T>());
}
+ /**
+ * Checks if moving certain member to certain class may lead to conflict (actually that means
+ * that class already has this member)
+ *
+ * @param member member to check
+ * @param aClass class where this member wanna be moved
+ * @return true if conflict exists.
+ */
+ public abstract boolean hasConflict(@NotNull T member, @NotNull PyClass aClass);
+
+ /**
+ * Returns all elements this member depends on.
+ *
+ * @param classWhereMemberDeclared class where member declared
+ * @param member member itself
+ * @param destinationClass where this member would be moved (or null if new class is unknown)
+ * @return collection of elements this member depends on excluding those, would be available in destination class
+ */
+ @NotNull
+ public static Collection<? extends PyElement> getAllDependencies(
+ @NotNull final PyClass classWhereMemberDeclared,
+ @NotNull final PyElement member,
+ @Nullable final PyClass destinationClass) {
+ final PyMemberInfo<PyElement> memberInfo = findMember(classWhereMemberDeclared, member);
+
+
+ final Collection<? extends PyElement> elementsToCheckDependency =
+ memberInfo.getMembersManager().getElementsToStoreReferences(Collections.singleton(member));
+
+ final MultiMap<PyClass, PyElement> dependencies = new MultiMap<PyClass, PyElement>();
+
+ final Collection<PyElement> result = new HashSet<PyElement>();
+ for (final MembersManager<? extends PyElement> manager : MANAGERS) {
+ for (final PyElement elementToCheckDependency : elementsToCheckDependency) {
+ dependencies.putAllValues(manager.getDependencies(elementToCheckDependency));
+ }
+ }
+
+ if (destinationClass != null) {
+ final Iterator<PyClass> classesIterator = dependencies.keySet().iterator();
+ while (classesIterator.hasNext()) {
+ final PyClass memberClass = classesIterator.next();
+ if (memberClass.equals(destinationClass) ||
+ ArrayUtil.contains(memberClass, destinationClass.getSuperClasses())) { // IF still would be available
+ classesIterator.remove();
+ }
+ }
+ }
+
+ for (final MembersManager<? extends PyElement> manager : MANAGERS) {
+ result.addAll(manager.getDependencies(dependencies));
+ }
+ result.addAll(dependencies.values());
+ return result;
+ }
+
+ /**
+ * Fetch dependencies this element depends on.
+ * Manager should return them in format "class, where member declared" -- "member itself".
+ * For example: if parameter is function, and this function uses field "foo" declared in class "bar", then manager (responsible for fields)
+ * returns "bar" -] reference to "foo"
+ *
+ * @param member member to check dependencies for
+ * @return dependencies
+ */
+ @NotNull
+ protected abstract MultiMap<PyClass, PyElement> getDependencies(@NotNull PyElement member);
+
+ /**
+ * Get dependencies by members and classes they declared in (obtained from {@link #getDependencies(com.jetbrains.python.psi.PyElement)})
+ * For example manager, responsible for "extends SomeClass" members may return list of classes
+ *
+ * @param usedElements class-to-element dependencies
+ * @return dependencies
+ */
+ @NotNull
+ protected abstract Collection<PyElement> getDependencies(@NotNull MultiMap<PyClass, PyElement> usedElements);
+
private static class PyMemberExtractor<T extends PyElement> implements Function<PyMemberInfo<T>, T> {
@SuppressWarnings("NullableProblems") //IDEA-120100
@Override
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java
index 264261e..7cba0a2 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java
@@ -3,13 +3,16 @@
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReference;
+import com.intellij.util.containers.MultiMap;
import com.jetbrains.NotNullPredicate;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.imports.AddImportHelper;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyFunctionBuilder;
-import com.jetbrains.python.psi.types.PyClassLikeType;
+import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.TypeEvalContext;
import com.jetbrains.python.refactoring.classes.PyClassRefactoringUtil;
import org.jetbrains.annotations.NotNull;
@@ -37,6 +40,26 @@
super(PyFunction.class);
}
+ @Override
+ public boolean hasConflict(@NotNull final PyFunction member, @NotNull final PyClass aClass) {
+ return NamePredicate.hasElementWithSameName(member, Arrays.asList(aClass.getMethods()));
+ }
+
+ @NotNull
+ @Override
+ protected Collection<PyElement> getDependencies(@NotNull final MultiMap<PyClass, PyElement> usedElements) {
+ return Collections.emptyList();
+ }
+
+ @NotNull
+ @Override
+ protected MultiMap<PyClass, PyElement> getDependencies(@NotNull final PyElement member) {
+ final MultiMap<PyClass, PyElement> result = new MultiMap<PyClass, PyElement>();
+ member.accept(new MyPyRecursiveElementVisitor(result));
+
+ return result;
+ }
+
@NotNull
@Override
protected List<PyElement> getMembersCouldBeMoved(@NotNull final PyClass pyClass) {
@@ -69,7 +92,7 @@
final PyFunctionBuilder functionBuilder = PyFunctionBuilder.copySignature(function, DECORATORS_MAY_BE_COPIED_TO_ABSTRACT);
functionBuilder.decorate(PyNames.ABSTRACTMETHOD);
final LanguageLevel level = LanguageLevel.forElement(destClass);
- PyClassRefactoringUtil.addMethods(destClass, functionBuilder.buildFunction(destClass.getProject(), level));
+ PyClassRefactoringUtil.addMethods(destClass, false, functionBuilder.buildFunction(destClass.getProject(), level));
classesToAddMetaAbc.add(destClass);
}
}
@@ -98,7 +121,7 @@
// TODO: Copy/Paste with PyClass.getMeta..
private static boolean addMetaAbcIfNeeded(@NotNull final PyClass aClass) {
final PsiFile file = aClass.getContainingFile();
- final PyClassLikeType type = aClass.getMetaClassType(TypeEvalContext.userInitiated(file));
+ final PyType type = aClass.getMetaClassType(TypeEvalContext.userInitiated(file));
if (type != null) {
return false; //User already has metaclass. He probably knows about metaclasses, so we should not add ABCMeta
}
@@ -227,4 +250,35 @@
return input.isToAbstract() == myAllowAbstractOnly;
}
}
+
+ private static class MyPyRecursiveElementVisitor extends PyRecursiveElementVisitor {
+ @NotNull
+ private final MultiMap<PyClass, PyElement> myResult;
+
+ private MyPyRecursiveElementVisitor(@NotNull final MultiMap<PyClass, PyElement> result) {
+ myResult = result;
+ }
+
+ @Override
+ public void visitPyCallExpression(final PyCallExpression node) {
+ // TODO: refactor, messy code
+ final PyExpression callee = node.getCallee();
+ if (callee != null) {
+ final PsiReference calleeRef = callee.getReference();
+ if (calleeRef != null) {
+ final PsiElement calleeDeclaration = calleeRef.resolve();
+ if (calleeDeclaration instanceof PyFunction) {
+ final PyFunction calleeFunction = (PyFunction)calleeDeclaration;
+ final PyClass clazz = calleeFunction.getContainingClass();
+ if (clazz != null) {
+ if (PyUtil.isInit(calleeFunction)) {
+ return; // Init call should not be marked as dependency
+ }
+ myResult.putValue(clazz, calleeFunction);
+ }
+ }
+ }
+ }
+ }
+ }
}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/NamePredicate.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/NamePredicate.java
new file mode 100644
index 0000000..7a5ddc6
--- /dev/null
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/NamePredicate.java
@@ -0,0 +1,45 @@
+package com.jetbrains.python.refactoring.classes.membersManager;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.intellij.navigation.NavigationItem;
+import com.jetbrains.NotNullPredicate;
+import com.jetbrains.python.psi.PyElement;
+import org.jetbrains.annotations.NotNull;
+
+
+/**
+ * Finds elements by name
+ *
+ * @author Ilya.Kazakevich
+ */
+class NamePredicate extends NotNullPredicate<PyElement> {
+ @NotNull
+ private final String myName;
+
+
+ NamePredicate(@NotNull final String name) {
+ myName = name;
+ }
+
+ @Override
+ protected boolean applyNotNull(@NotNull final PyElement input) {
+ return myName.equals(input.getName());
+ }
+
+ /**
+ * Checks if collection has {@link com.jetbrains.python.psi.PyElement} with name equals to name of provided element.
+ * If element has no name -- returns false any way.
+ * @param needle element to take name from
+ * @param stock collection elements to search between
+ * @return true if stock contains element with name equal to needle's name
+ */
+ static boolean hasElementWithSameName(@NotNull final NavigationItem needle, @NotNull final Iterable<? extends PyElement> stock) {
+ final String name = needle.getName();
+ if (name != null) {
+ final Optional<? extends PyElement> optional = Iterables.tryFind(stock, new NamePredicate(name));
+ return optional.isPresent();
+ }
+ return false;
+ }
+}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/PyMemberInfo.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/PyMemberInfo.java
index 650350b..819ab90 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/PyMemberInfo.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/PyMemberInfo.java
@@ -16,6 +16,7 @@
package com.jetbrains.python.refactoring.classes.membersManager;
import com.intellij.refactoring.classMembers.MemberInfoBase;
+import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -29,7 +30,7 @@
private final boolean myCouldBeAbstract;
/**
- * TODO: Doc new param
+ * @param couldBeAbstract if element could be marked as abstract (like abstract method)
* @param member element itself
* @param isStatic is it static or not?
* @param displayName element display name
@@ -72,4 +73,13 @@
public int hashCode() {
return getMember().hashCode();
}
+
+ /**
+ * Checks if moving this member to some class may create conflict.
+ * @param destinationClass destination class to check
+ * @return true if conflict.
+ */
+ public boolean hasConflict(@NotNull final PyClass destinationClass) {
+ return myMembersManager.hasConflict(myMember, destinationClass);
+ }
}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/SuperClassesManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/SuperClassesManager.java
index 82ce209..92ffe76 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/SuperClassesManager.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/SuperClassesManager.java
@@ -3,6 +3,7 @@
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.intellij.refactoring.RefactoringBundle;
+import com.intellij.util.containers.MultiMap;
import com.jetbrains.NotNullPredicate;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.*;
@@ -10,10 +11,7 @@
import com.jetbrains.python.refactoring.classes.ui.PyClassCellRenderer;
import org.jetbrains.annotations.NotNull;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
/**
* Plugin that moves superclasses from one class to another
@@ -31,6 +29,23 @@
@NotNull
@Override
+ protected Collection<PyElement> getDependencies(@NotNull final MultiMap<PyClass, PyElement> usedElements) {
+ return Lists.<PyElement>newArrayList(usedElements.keySet());
+ }
+
+ @NotNull
+ protected MultiMap<PyClass, PyElement> getDependencies(@NotNull PyElement member) {
+ return MultiMap.emptyInstance();
+ }
+
+ @Override
+ public boolean hasConflict(@NotNull final PyClass member, @NotNull final PyClass aClass) {
+ final List<PyExpression> expressionList = getExpressionsBySuperClass(aClass, Collections.singleton(member));
+ return !expressionList.isEmpty();
+ }
+
+ @NotNull
+ @Override
protected List<PyElement> getMembersCouldBeMoved(@NotNull final PyClass pyClass) {
return Lists.<PyElement>newArrayList(Collections2.filter(Arrays.asList(pyClass.getSuperClasses()), NO_FAKE_SUPER_CLASSES));
}
@@ -44,19 +59,37 @@
PyClassRefactoringUtil.addSuperclasses(from.getProject(), destClass, elements.toArray(new PyClass[members.size()]));
}
+ final List<PyExpression> expressionsToDelete = getExpressionsBySuperClass(from, elements);
+ for (final PyExpression expressionToDelete : expressionsToDelete) {
+ expressionToDelete.delete();
+ }
+
+ return Collections.emptyList(); //Hack: we know that "superclass expression" can't have reference
+ }
+
+ /**
+ * Returns superclass expressions that are resolved to one or more classes from collection
+ * @param from class to get superclass expressions from
+ * @param classes classes to check superclasses against
+ * @return collection of expressions that are resolved to one or more class from classes param
+ */
+ @NotNull
+ private static List<PyExpression> getExpressionsBySuperClass(@NotNull final PyClass from, @NotNull final Collection<PyClass> classes) {
+ final List<PyExpression> expressionsToDelete = new ArrayList<PyExpression>(classes.size());
+
for (final PyExpression expression : from.getSuperClassExpressions()) {
// Remove all superclass expressions that point to class from memberinfo
if (!(expression instanceof PyQualifiedExpression)) {
continue;
}
final PyReferenceExpression reference = (PyReferenceExpression)expression;
- for (final PyClass element : elements) {
+ for (final PyClass element : classes) {
if (reference.getReference().isReferenceTo(element)) {
- expression.delete();
+ expressionsToDelete.add(expression);
}
}
}
- return Collections.emptyList(); //Hack: we know that "superclass expression" can't have reference
+ return expressionsToDelete;
}
@NotNull
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedPresenterImpl.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedPresenterImpl.java
index 118b3d6..57f437f 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedPresenterImpl.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedPresenterImpl.java
@@ -1,12 +1,17 @@
package com.jetbrains.python.refactoring.classes.membersManager.vp;
-import com.intellij.psi.PsiElement;
import com.intellij.refactoring.RefactoringBundle;
+import com.intellij.refactoring.classMembers.MemberInfoModel;
import com.intellij.util.containers.MultiMap;
import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.refactoring.classes.PyMemberInfoStorage;
+import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo;
import org.jetbrains.annotations.NotNull;
+import java.util.ArrayList;
+import java.util.Collection;
+
/**
* All presenters that use members inherits this class.
* <strong>Warning</strong>: Do not inherit it directly.
@@ -14,35 +19,51 @@
* or {@link com.jetbrains.python.refactoring.classes.membersManager.vp.MembersBasedPresenterWithPreviewImpl} instead
*
* @param <T> view for that presenter
+ * @param <M> Type of model {@link #myModel}
* @author Ilya.Kazakevich
*/
-abstract class MembersBasedPresenterImpl<T extends MembersBasedView<?>> implements MembersBasedPresenter {
+abstract class MembersBasedPresenterImpl<T extends MembersBasedView<?>,
+ M extends MemberInfoModel<PyElement, PyMemberInfo<PyElement>>> implements MembersBasedPresenter {
@NotNull
protected final T myView;
@NotNull
protected final PyClass myClassUnderRefactoring;
@NotNull
protected final PyMemberInfoStorage myStorage;
+ /**
+ * Member model
+ */
+ @NotNull
+ protected final M myModel;
/**
* @param view View for presenter
* @param classUnderRefactoring class to be refactored
* @param infoStorage info storage
+ * @param model Member model (to be used for dependencies checking)
*/
MembersBasedPresenterImpl(@NotNull final T view,
@NotNull final PyClass classUnderRefactoring,
- @NotNull final PyMemberInfoStorage infoStorage) {
+ @NotNull final PyMemberInfoStorage infoStorage,
+ @NotNull final M model) {
myView = view;
myClassUnderRefactoring = classUnderRefactoring;
myStorage = infoStorage;
+ myModel = model;
}
//TODO: Mark Async ?
@Override
public void okClicked() {
+ final MultiMap<PyClass, PyMemberInfo<?>> conflicts = getConflicts();
+ final Collection<PyMemberInfo<?>> dependencyConflicts = new ArrayList<PyMemberInfo<?>>();
+ for (final PyMemberInfo<PyElement> memberInfo : myStorage.getClassMemberInfos(myClassUnderRefactoring)) {
+ if (myModel.checkForProblems(memberInfo) != MemberInfoModel.OK) {
+ dependencyConflicts.add(memberInfo);
+ }
+ }
- final MultiMap<PsiElement, String> conflicts = getConflicts();
- if (conflicts.isEmpty() || myView.showConflictsDialog(conflicts)) {
+ if ((conflicts.isEmpty() && dependencyConflicts.isEmpty()) || myView.showConflictsDialog(conflicts, dependencyConflicts)) {
try {
validateView();
doRefactor();
@@ -75,9 +96,29 @@
abstract void doRefactor();
/**
+ * Checks if one of destination classes already has members that should be moved, so conflict would take place.
+ *
* @return map of conflicts (if any)
+ * @see #getDestClassesToCheckConflicts()
*/
@NotNull
- protected abstract MultiMap<PsiElement, String> getConflicts();
+ protected final MultiMap<PyClass, PyMemberInfo<?>> getConflicts() {
+ final MultiMap<PyClass, PyMemberInfo<?>> result = new MultiMap<PyClass, PyMemberInfo<?>>();
+ final Collection<PyMemberInfo<PyElement>> memberInfos = myView.getSelectedMemberInfos();
+ for (final PyClass destinationClass : getDestClassesToCheckConflicts()) {
+ for (final PyMemberInfo<PyElement> pyMemberInfo : memberInfos) {
+ if (pyMemberInfo.hasConflict(destinationClass)) {
+ result.putValue(destinationClass, pyMemberInfo);
+ }
+ }
+ }
+ return result;
+ }
+ /**
+ * @return classes where this refactoring will move members. To be used to check for conflicts (if one of target classes already has members)
+ * @see #getConflicts()
+ */
+ @NotNull
+ protected abstract Iterable<? extends PyClass> getDestClassesToCheckConflicts();
}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedPresenterNoPreviewImpl.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedPresenterNoPreviewImpl.java
index 199ac7a..dfbe3da 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedPresenterNoPreviewImpl.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedPresenterNoPreviewImpl.java
@@ -2,28 +2,35 @@
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.refactoring.classMembers.MemberInfoModel;
import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.refactoring.classes.PyMemberInfoStorage;
+import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo;
import org.jetbrains.annotations.NotNull;
/**
* Presenter that has not preview. Children should implement {@link #refactorNoPreview()}.
* To "preview" button would be displayed
+ *
* @param <T> view for this presenter
+ * @param <M> Type of model
* @author Ilya.Kazakevich
*/
-public abstract class MembersBasedPresenterNoPreviewImpl<T extends MembersBasedView<?>> extends MembersBasedPresenterImpl<T> {
+public abstract class MembersBasedPresenterNoPreviewImpl<T extends MembersBasedView<?>,
+ M extends MemberInfoModel<PyElement, PyMemberInfo<PyElement>>> extends MembersBasedPresenterImpl<T, M> {
/**
- *
- * @param view view for this presenter
+ * @param view view for this presenter
* @param classUnderRefactoring class to refactor
- * @param infoStorage info storage
+ * @param infoStorage info storage
+ * @param model Member model (to be used for dependencies checking)
*/
protected MembersBasedPresenterNoPreviewImpl(@NotNull final T view,
@NotNull final PyClass classUnderRefactoring,
- @NotNull final PyMemberInfoStorage infoStorage) {
- super(view, classUnderRefactoring, infoStorage);
+ @NotNull final PyMemberInfoStorage infoStorage,
+ @NotNull final M model) {
+ super(view, classUnderRefactoring, infoStorage, model);
}
@Override
@@ -36,12 +43,7 @@
CommandProcessor.getInstance().executeCommand(myClassUnderRefactoring.getProject(), new Runnable() {
@Override
public void run() {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- refactorNoPreview();
- }
- });
+ ApplicationManager.getApplication().runWriteAction(new MyRunnableRefactoring());
}
}, getCommandName(), null);
myView.close();
@@ -57,4 +59,11 @@
* Do refactor with out of preview. Implement this method to do refactoring.
*/
protected abstract void refactorNoPreview();
+
+ private class MyRunnableRefactoring implements Runnable {
+ @Override
+ public void run() {
+ refactorNoPreview();
+ }
+ }
}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedPresenterWithPreviewImpl.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedPresenterWithPreviewImpl.java
index ab68548..8950a14 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedPresenterWithPreviewImpl.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedPresenterWithPreviewImpl.java
@@ -1,8 +1,11 @@
package com.jetbrains.python.refactoring.classes.membersManager.vp;
import com.intellij.refactoring.BaseRefactoringProcessor;
+import com.intellij.refactoring.classMembers.MemberInfoModel;
import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.refactoring.classes.PyMemberInfoStorage;
+import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo;
import org.jetbrains.annotations.NotNull;
/**
@@ -11,20 +14,24 @@
* "Preview" button would be displayed.
*
* @param <T> view for this presenter
+ * @param <M> Type of model
* @author Ilya.Kazakevich
*/
-public abstract class MembersBasedPresenterWithPreviewImpl<T extends MembersBasedView<?>> extends MembersBasedPresenterImpl<T> {
+public abstract class MembersBasedPresenterWithPreviewImpl<T extends MembersBasedView<?>,
+ M extends MemberInfoModel<PyElement, PyMemberInfo<PyElement>>> extends MembersBasedPresenterImpl<T, M> {
/**
* @param view view for this presenter
* @param classUnderRefactoring class to refactor
* @param infoStorage info storage
+ * @param model Member model (to be used for dependencies checking)
*/
protected MembersBasedPresenterWithPreviewImpl(@NotNull final T view,
@NotNull final PyClass classUnderRefactoring,
- @NotNull final PyMemberInfoStorage infoStorage) {
- super(view, classUnderRefactoring, infoStorage);
+ @NotNull final PyMemberInfoStorage infoStorage,
+ @NotNull final M model) {
+ super(view, classUnderRefactoring, infoStorage, model);
}
@Override
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedView.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedView.java
index 70496d0..01a7eca 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedView.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedView.java
@@ -1,8 +1,8 @@
package com.jetbrains.python.refactoring.classes.membersManager.vp;
-import com.intellij.psi.PsiElement;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.util.containers.MultiMap;
+import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo;
import org.jetbrains.annotations.NotNull;
@@ -22,10 +22,16 @@
/**
* Display conflict dialogs.
*
- * @param conflicts conflicts.
+ * @param duplicatesConflict duplicates conflicts : that means destination class has the same member.
+ * If member "foo" already exists in class "bar": pass [bar] -] [foo].
+ * @param dependenciesConflicts dependency conflict: list of elements used by member under refactoring and would not be available
+ * at new destination. If user wants to move method, that uses field "bar" which would not be available at new class,
+ * pass [bar] field
* @return true if user's choice is "continue". False if "cancel"
*/
- boolean showConflictsDialog(@NotNull MultiMap<PsiElement, String> conflicts);
+ boolean showConflictsDialog(
+ @NotNull MultiMap<PyClass, PyMemberInfo<?>> duplicatesConflict,
+ @NotNull Collection<PyMemberInfo<?>> dependenciesConflicts);
/**
* Displays error message
diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedViewSwingImpl.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedViewSwingImpl.java
index 1fc5e53..a8df16e 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedViewSwingImpl.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/vp/MembersBasedViewSwingImpl.java
@@ -2,13 +2,15 @@
import com.google.common.base.Preconditions;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
-import com.intellij.psi.PsiElement;
+import com.intellij.openapi.util.Pair;
import com.intellij.refactoring.BaseRefactoringProcessor;
-import com.intellij.refactoring.ui.ConflictsDialog;
import com.intellij.refactoring.ui.RefactoringDialog;
import com.intellij.util.containers.MultiMap;
+import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElement;
+import com.jetbrains.python.refactoring.classes.membersManager.MembersConflictDialog;
import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo;
import com.jetbrains.python.refactoring.classes.ui.PyMemberSelectionPanel;
import org.jetbrains.annotations.NotNull;
@@ -72,10 +74,12 @@
//TODO: Take this from presenter to prevent inconsistence: now it is possible to create view that supports abstract backed by presenter that does not. And vice versa.
}
+
@Override
- public boolean showConflictsDialog(@NotNull final MultiMap<PsiElement, String> conflicts) {
- Preconditions.checkArgument(!conflicts.isEmpty(), "Can't show dialog for empty conflicts");
- final ConflictsDialog conflictsDialog = new ConflictsDialog(myProject, conflicts);
+ public boolean showConflictsDialog(@NotNull final MultiMap<PyClass, PyMemberInfo<?>> duplicatesConflict,
+ @NotNull final Collection<PyMemberInfo<?>> dependenciesConflicts) {
+ Preconditions.checkArgument(!(duplicatesConflict.isEmpty() && dependenciesConflicts.isEmpty()), "Can't show dialog for empty conflicts");
+ final DialogWrapper conflictsDialog = new MembersConflictDialog(myProject, duplicatesConflict, dependenciesConflicts);
conflictsDialog.show();
return conflictsDialog.isOK();
}
@@ -133,6 +137,7 @@
public void initAndShow() {
Preconditions.checkArgument(myConfigured, "Not configured, run 'configure' first!");
init();
+ myPyMemberSelectionPanel.redraw(); // To display errors for checked member
show();
}
-}
+}
\ No newline at end of file
diff --git a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpConflictsUtil.java b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpConflictsUtil.java
deleted file mode 100644
index 9c63a62..0000000
--- a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpConflictsUtil.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.refactoring.classes.pullUp;
-
-import com.intellij.psi.PsiElement;
-import com.intellij.refactoring.RefactoringBundle;
-import com.intellij.refactoring.util.RefactoringUIUtil;
-import com.intellij.util.containers.MultiMap;
-import com.jetbrains.python.psi.PyClass;
-import com.jetbrains.python.psi.PyElement;
-import com.jetbrains.python.psi.PyFunction;
-import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Collection;
-
-/**
- * @author Dennis.Ushakov
- */
-final class PyPullUpConflictsUtil {
- private PyPullUpConflictsUtil() {
- }
-
- @NotNull
- static MultiMap<PsiElement, String> checkConflicts(final Collection<PyMemberInfo<PyElement>> infos, @NotNull final PyClass superClass) {
- final MultiMap<PsiElement, String> conflictsList = new MultiMap<PsiElement, String>();
- for (PyMemberInfo<PyElement> info : infos) {
- PsiElement member = info.getMember();
- boolean isConflict = false;
- //TODO: Delegate to MemeberManagers here
- if (member instanceof PyFunction) {
- final String name = ((PyFunction)member).getName();
- if (name == null) continue;
- final PyFunction superClassMethod = superClass.findMethodByName(name, false);
- isConflict = superClassMethod != null;
- } else if (member instanceof PyClass) {
- final PyClass clazz = (PyClass)member;
- for (PyClass aClass : superClass.getSuperClasses()) {
- if (aClass == clazz) {
- conflictsList.putValue(superClass,
- RefactoringUIUtil.getDescription(superClass, false) + " already extends " + RefactoringUIUtil.getDescription(clazz, false));
- }
- }
- }
-
- if (isConflict) {
- final String message = RefactoringBundle.message("0.already.contains.a.1",
- RefactoringUIUtil.getDescription(superClass, false),
- RefactoringUIUtil.getDescription(member, false));
- conflictsList.putValue(superClass, message);
- }
- }
-
- return conflictsList;
- }
-}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpHandler.java b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpHandler.java
index 6dcb3b6..4fa0eac 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpHandler.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpHandler.java
@@ -17,8 +17,6 @@
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
-import com.intellij.refactoring.RefactoringBundle;
-import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.refactoring.classes.PyClassRefactoringHandler;
@@ -39,14 +37,10 @@
@NotNull final PyMemberInfoStorage infoStorage,
@NotNull final Editor editor) {
//TODO: Move to vp (presenter) as well
+ final PyPullUpNothingToRefactorMessage nothingToRefactor = new PyPullUpNothingToRefactorMessage(project, editor, classUnderRefactoring);
- if (PyAncestorsUtils.getAncestorsUnderUserControl(classUnderRefactoring).isEmpty() ||
- infoStorage.getClassMemberInfos(classUnderRefactoring).isEmpty()) {
- CommonRefactoringUtil.showErrorHint(project, editor, PyBundle
- .message("refactoring.pull.up.error.cannot.perform.refactoring.no.base.classes",
- classUnderRefactoring.getName()), RefactoringBundle.message("pull.members.up.title"),
- "members.pull.up"
- );
+ if (PyAncestorsUtils.getAncestorsUnderUserControl(classUnderRefactoring).isEmpty()) {
+ nothingToRefactor.showNothingToRefactor();
return;
}
@@ -62,13 +56,13 @@
@NotNull
@Override
public PyPullUpView createView(@NotNull final PyPullUpPresenter presenter) {
- return new PyPullUpViewSwingImpl(project, presenter, classUnderRefactoring);
+ return new PyPullUpViewSwingImpl(project, presenter, classUnderRefactoring, nothingToRefactor);
}
}
);
-
}
+
@Override
protected String getTitle() {
return REFACTORING_NAME;
diff --git a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpInfoModel.java b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpInfoModel.java
new file mode 100644
index 0000000..c86907d
--- /dev/null
+++ b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpInfoModel.java
@@ -0,0 +1,52 @@
+package com.jetbrains.python.refactoring.classes.pullUp;
+
+import com.intellij.refactoring.classMembers.AbstractUsesDependencyMemberInfoModel;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyElement;
+import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Dependencies model for PyPullUp refactoring
+* @author Ilya.Kazakevich
+*/
+class PyPullUpInfoModel extends AbstractUsesDependencyMemberInfoModel<PyElement, PyClass, PyMemberInfo<PyElement>> {
+ @NotNull
+ private final PyPullUpView myView;
+
+
+ PyPullUpInfoModel(@NotNull final PyClass classUnderRefactoring,
+ @NotNull final PyPullUpView view) {
+ super(classUnderRefactoring, null, false);
+ myView = view;
+ }
+
+ @Override
+ public boolean isAbstractEnabled(final PyMemberInfo<PyElement> member) {
+ return member.isCouldBeAbstract() && isMemberEnabled(member); // TODO: copy paste with other models, get rid of
+ }
+
+ @Override
+ public int checkForProblems(@NotNull final PyMemberInfo<PyElement> member) {
+ return member.isChecked() ? OK : super.checkForProblems(member);
+ }
+
+
+ @Override
+ protected int doCheck(@NotNull final PyMemberInfo<PyElement> memberInfo, final int problem) {
+ return problem;
+ }
+
+ @Override
+ public boolean isMemberEnabled(final PyMemberInfo<PyElement> member) {
+ final PyClass currentSuperClass = myView.getSelectedParent();
+ if (member.getMember() instanceof PyClass) {
+ //TODO: Delegate to Memebers Managers
+ final PyClass memberClass = (PyClass)member.getMember();
+ if (memberClass.isSubclass(currentSuperClass) || currentSuperClass.isSubclass(memberClass)) {
+ return false; //Class is already parent of superclass
+ }
+ }
+ return true;
+ }
+}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpNothingToRefactorMessage.java b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpNothingToRefactorMessage.java
new file mode 100644
index 0000000..cbb599c
--- /dev/null
+++ b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpNothingToRefactorMessage.java
@@ -0,0 +1,48 @@
+package com.jetbrains.python.refactoring.classes.pullUp;
+
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.refactoring.RefactoringBundle;
+import com.intellij.refactoring.util.CommonRefactoringUtil;
+import com.jetbrains.python.PyBundle;
+import com.jetbrains.python.psi.PyClass;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Displays "nothing to refactor" message
+ * @author Ilya.Kazakevich
+ */
+class PyPullUpNothingToRefactorMessage {
+
+ @NotNull
+ private final Project myProject;
+ @NotNull
+ private final Editor myEditor;
+ @NotNull
+ private final PyClass myClassUnderRefactoring;
+
+ /**
+ *
+ * @param project project to be used
+ * @param editor editor to be used
+ * @param classUnderRefactoring class user refactors
+ */
+ PyPullUpNothingToRefactorMessage(@NotNull final Project project,
+ @NotNull final Editor editor,
+ @NotNull final PyClass classUnderRefactoring) {
+ myProject = project;
+ myEditor = editor;
+ myClassUnderRefactoring = classUnderRefactoring;
+ }
+
+ /**
+ * Display message
+ */
+ void showNothingToRefactor() {
+ CommonRefactoringUtil.showErrorHint(myProject, myEditor, PyBundle
+ .message("refactoring.pull.up.error.cannot.perform.refactoring.no.base.classes",
+ myClassUnderRefactoring.getName()), RefactoringBundle.message("pull.members.up.title"),
+ "members.pull.up"
+ );
+ }
+}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenter.java b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenter.java
index d98433f..1e97f77 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenter.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenter.java
@@ -27,4 +27,8 @@
*/
public interface PyPullUpPresenter extends MembersBasedPresenter {
+ /**
+ * To be called when user changed parent
+ */
+ void parentChanged();
}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenterImpl.java b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenterImpl.java
index 83c2f0b..b78433a 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenterImpl.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenterImpl.java
@@ -17,11 +17,8 @@
import com.google.common.base.Preconditions;
import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiElement;
import com.intellij.refactoring.BaseRefactoringProcessor;
-import com.intellij.refactoring.classMembers.AbstractUsesDependencyMemberInfoModel;
import com.intellij.refactoring.util.CommonRefactoringUtil;
-import com.intellij.util.containers.MultiMap;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.psi.PyUtil;
@@ -38,7 +35,7 @@
*
* @author Ilya.Kazakevich
*/
-class PyPullUpPresenterImpl extends MembersBasedPresenterWithPreviewImpl<PyPullUpView> implements PyPullUpPresenter {
+class PyPullUpPresenterImpl extends MembersBasedPresenterWithPreviewImpl<PyPullUpView, PyPullUpInfoModel> implements PyPullUpPresenter {
@NotNull
private final Collection<PyClass> myParents;
@@ -48,7 +45,7 @@
* @param clazz class to refactor
*/
PyPullUpPresenterImpl(@NotNull final PyPullUpView view, @NotNull final PyMemberInfoStorage infoStorage, @NotNull final PyClass clazz) {
- super(view, clazz, infoStorage);
+ super(view, clazz, infoStorage, new PyPullUpInfoModel(clazz, view));
myParents = PyAncestorsUtils.getAncestorsUnderUserControl(clazz);
Preconditions.checkArgument(!myParents.isEmpty(), "No parents found");
}
@@ -57,8 +54,23 @@
@Override
public void launch() {
myView.configure(
- new PyPullUpViewInitializationInfo(new PyPullUpInfoModel(), myStorage.getClassMemberInfos(myClassUnderRefactoring), myParents));
- myView.initAndShow();
+ new PyPullUpViewInitializationInfo(myModel, myStorage.getClassMemberInfos(myClassUnderRefactoring), myParents));
+
+ // If there is no enabled member then only error should be displayed
+
+ boolean atLeastOneEnabled = false;
+ for (final PyMemberInfo<PyElement> info : myStorage.getClassMemberInfos(myClassUnderRefactoring)) {
+ if (myModel.isMemberEnabled(info)) {
+ atLeastOneEnabled = true;
+ }
+ }
+
+
+ if (atLeastOneEnabled) {
+ myView.initAndShow();
+ } else {
+ myView.showNothingToRefactor();
+ }
}
@Override
@@ -92,55 +104,15 @@
return true;
}
-
@Override
- @NotNull
- public MultiMap<PsiElement, String> getConflicts() {
- final Collection<PyMemberInfo<PyElement>> infos = myView.getSelectedMemberInfos();
- final PyClass superClass = myView.getSelectedParent();
- return PyPullUpConflictsUtil.checkConflicts(infos, superClass);
+ public void parentChanged() {
+ myModel.setSuperClass(myView.getSelectedParent());
}
- private class PyPullUpInfoModel extends AbstractUsesDependencyMemberInfoModel<PyElement, PyClass, PyMemberInfo<PyElement>> {
-
- PyPullUpInfoModel() {
- super(myClassUnderRefactoring, null, false);
- }
-
- @Override
- public boolean isAbstractEnabled(final PyMemberInfo<PyElement> member) {
- return member.isCouldBeAbstract() && isMemberEnabled(member); // TODO: copy paste with other models, get rid of
- }
-
- @Override
- public int checkForProblems(@NotNull final PyMemberInfo<PyElement> member) {
- return member.isChecked() ? OK : super.checkForProblems(member);
- }
-
-
- @Override
- protected int doCheck(@NotNull final PyMemberInfo<PyElement> memberInfo, final int problem) {
- if (problem == ERROR && memberInfo.isStatic()) {
- return WARNING;
- }
- return problem;
- }
-
- @Override
- public boolean isMemberEnabled(final PyMemberInfo<PyElement> member) {
- final PyClass currentSuperClass = myView.getSelectedParent();
- if (member.getMember() instanceof PyClass) {
- //TODO: Delegate to Memebers Managers
- final PyClass memberClass = (PyClass)member.getMember();
- if (memberClass.isSubclass(currentSuperClass) || currentSuperClass.isSubclass(memberClass)) {
- return false; //Class is already parent of superclass
- }
- }
- if (!PyPullUpConflictsUtil.checkConflicts(Collections.singletonList(member), myView.getSelectedParent()).isEmpty()) {
- return false; //Member has conflict
- }
- return (!myStorage.getDuplicatedMemberInfos(currentSuperClass).contains(member)) && member.getMember() != currentSuperClass;
- }
+ @NotNull
+ @Override
+ protected Iterable<? extends PyClass> getDestClassesToCheckConflicts() {
+ return Collections.singletonList(myView.getSelectedParent());
}
}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpView.java b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpView.java
index b0a42e0..0a770ea 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpView.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpView.java
@@ -31,4 +31,9 @@
*/
@NotNull
PyClass getSelectedParent();
+
+ /**
+ * Display "nothing to refactor" message.
+ */
+ void showNothingToRefactor();
}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpViewSwingImpl.java b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpViewSwingImpl.java
index 2a457f8..3f0fa2a 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpViewSwingImpl.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpViewSwingImpl.java
@@ -39,15 +39,23 @@
private final ComboBox myParentsCombo;
@NotNull
private final DefaultComboBoxModel myParentsComboBoxModel;
+ @NotNull
+ private final PyPullUpNothingToRefactorMessage myNothingToRefactorMessage;
/**
* @param project project where refactoring takes place
* @param presenter presenter for this view
* @param clazz class to refactor
+ * @param nothingToRefactorMessage class that displays message "nothing to refactor" when presenter calls {@link #showNothingToRefactor()}
*/
- PyPullUpViewSwingImpl(@NotNull final Project project, @NotNull final PyPullUpPresenter presenter, @NotNull final PyClass clazz) {
+ PyPullUpViewSwingImpl(
+ @NotNull final Project project,
+ @NotNull final PyPullUpPresenter presenter,
+ @NotNull final PyClass clazz,
+ @NotNull final PyPullUpNothingToRefactorMessage nothingToRefactorMessage) {
super(project, presenter, RefactoringBundle.message("members.to.be.pulled.up"), true);
setTitle(PyPullUpHandler.REFACTORING_NAME);
+ myNothingToRefactorMessage = nothingToRefactorMessage;
myParentsComboBoxModel = new DefaultComboBoxModel();
@@ -91,7 +99,10 @@
return (PyClass)myParentsComboBoxModel.getSelectedItem();
}
-
+ @Override
+ public void showNothingToRefactor() {
+ myNothingToRefactorMessage.showNothingToRefactor();
+ }
@Override
public void configure(@NotNull final PyPullUpViewInitializationInfo configInfo) {
@@ -99,6 +110,7 @@
for (final PyClass parent : configInfo.getParents()) {
myParentsComboBoxModel.addElement(parent);
}
+ myPresenter.parentChanged();
myParentsCombo.addItemListener(this);
}
@@ -106,6 +118,7 @@
public void itemStateChanged(final ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
myPyMemberSelectionPanel.redraw();
+ myPresenter.parentChanged();
}
}
}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownConflicts.java b/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownConflicts.java
deleted file mode 100644
index 9eee6c9..0000000
--- a/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownConflicts.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.refactoring.classes.pushDown;
-
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.Comparing;
-import com.intellij.psi.PsiElement;
-import com.intellij.refactoring.RefactoringBundle;
-import com.intellij.refactoring.util.RefactoringUIUtil;
-import com.intellij.util.Function;
-import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.containers.MultiMap;
-import com.jetbrains.python.psi.*;
-import com.jetbrains.python.psi.resolve.PyResolveContext;
-import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * @author Dennis.Ushakov
- */
-class PyPushDownConflicts {
- private static final Logger LOG = Logger.getInstance(PyPushDownProcessor.class.getName());
-
- private final PyClass myClass;
- private final Collection<PyMemberInfo<PyElement>> myMembers;
- private final MultiMap<PsiElement, String> myConflicts;
-
- public PyPushDownConflicts(final PyClass clazz, final Collection<PyMemberInfo<PyElement>> members) {
- myClass = clazz;
- myMembers = members;
- myConflicts = new MultiMap<PsiElement, String>();
- }
-
- MultiMap<PsiElement, String> getConflicts() {
- return myConflicts;
- }
-
- void checkTargetClassConflicts(PyClass clazz) {
- checkPlacementConflicts(clazz);
- }
-
- private void checkPlacementConflicts(PyClass clazz) {
- for (PyMemberInfo<PyElement> member : myMembers) {
- final PyElement element = member.getMember();
- if (element instanceof PyFunction) {
- for (PyFunction function : clazz.getMethods()) {
- if (Comparing.strEqual(function.getName(), element.getName())) {
- final String message = RefactoringBundle.message("0.is.already.overridden.in.1",
- RefactoringUIUtil.getDescription(element, false),
- RefactoringUIUtil.getDescription(clazz, false));
- myConflicts.putValue(element, message);
- }
- }
- } else if (element instanceof PyClass) {
- } else LOG.error("unmatched member class " + clazz.getClass());
- }
- }
-
- public void checkSourceClassConflicts() {
- final List<PyElement> elements = ContainerUtil.map(myMembers, new Function<PyMemberInfo<PyElement>, PyElement>() {
- public PyElement fun(PyMemberInfo<PyElement> pyMemberInfo) {
- return pyMemberInfo.getMember();
- }
- });
- for (PyFunction pyFunction : myClass.getMethods()) {
- final UsedMembersCollector collector = new UsedMembersCollector(elements);
- pyFunction.accept(collector);
- final List<PyElement> conflicts = collector.getCollection();
-
- for (PyElement conflict : conflicts) {
- final String message = RefactoringBundle.message("0.uses.1.which.is.pushed.down",
- RefactoringUIUtil.getDescription(pyFunction, false),
- RefactoringUIUtil.getDescription(conflict, false));
- myConflicts.putValue(pyFunction, message);
- }
- }
- }
-
- private static class UsedMembersCollector extends PyRecursiveElementVisitor {
- private final List<PyElement> myCollection = new ArrayList<PyElement>();
- private final Collection<PyElement> myMovedMembers;
-
- private UsedMembersCollector(Collection<PyElement> movedMembers) {
- myMovedMembers = movedMembers;
- }
-
- @Override
- public void visitPyCallExpression(PyCallExpression node) {
- final Callable function = node.resolveCalleeFunction(PyResolveContext.noImplicits());
- if (function != null && myMovedMembers.contains(function)) {
- myCollection.add(function);
- }
- }
-
- public List<PyElement> getCollection() {
- return myCollection;
- }
- }
-}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownPresenterImpl.java b/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownPresenterImpl.java
index 1e9cabd..ce9306f 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownPresenterImpl.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownPresenterImpl.java
@@ -1,10 +1,9 @@
package com.jetbrains.python.refactoring.classes.pushDown;
import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiElement;
import com.intellij.refactoring.BaseRefactoringProcessor;
+import com.intellij.refactoring.classMembers.MemberInfoModel;
import com.intellij.refactoring.classMembers.UsedByDependencyMemberInfoModel;
-import com.intellij.util.containers.MultiMap;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.psi.PyUtil;
@@ -17,7 +16,7 @@
/**
* @author Ilya.Kazakevich
*/
-public class PyPushDownPresenterImpl extends MembersBasedPresenterWithPreviewImpl<PyPushDownView> implements PyPushDownPresenter {
+public class PyPushDownPresenterImpl extends MembersBasedPresenterWithPreviewImpl<PyPushDownView, MemberInfoModel<PyElement, PyMemberInfo<PyElement>>> implements PyPushDownPresenter {
@NotNull
private final Project myProject;
@@ -25,7 +24,7 @@
@NotNull final PyPushDownView view,
@NotNull final PyClass classUnderRefactoring,
@NotNull final PyMemberInfoStorage infoStorage) {
- super(view, classUnderRefactoring, infoStorage);
+ super(view, classUnderRefactoring, infoStorage, new UsedByDependencyMemberInfoModel<PyElement, PyClass, PyMemberInfo<PyElement>>(classUnderRefactoring));
myProject = project;
}
@@ -37,16 +36,14 @@
@NotNull
@Override
- protected MultiMap<PsiElement, String> getConflicts() {
- return new PyPushDownConflicts(myClassUnderRefactoring, myStorage.getClassMemberInfos(myClassUnderRefactoring)).getConflicts();
+ protected Iterable<? extends PyClass> getDestClassesToCheckConflicts() {
+ return PyPushDownProcessor.getInheritors(myClassUnderRefactoring);
}
@Override
public void launch() {
- UsedByDependencyMemberInfoModel<PyElement, PyClass, PyMemberInfo<PyElement>> model =
- new UsedByDependencyMemberInfoModel<PyElement, PyClass, PyMemberInfo<PyElement>>(myClassUnderRefactoring);
myView
- .configure(new MembersViewInitializationInfo(model, PyUtil.filterOutObject(myStorage.getClassMemberInfos(myClassUnderRefactoring))));
+ .configure(new MembersViewInitializationInfo(myModel, PyUtil.filterOutObject(myStorage.getClassMemberInfos(myClassUnderRefactoring))));
myView.initAndShow();
}
}
diff --git a/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownProcessor.java b/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownProcessor.java
index a0fcf53..283dd72 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownProcessor.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownProcessor.java
@@ -44,10 +44,19 @@
@NotNull
private static PyClass[] getChildren(@NotNull final PyClass from) {
- Collection<PyClass> all = PyClassInheritorsSearch.search(from, false).findAll();
+ final Collection<PyClass> all = getInheritors(from);
return all.toArray(new PyClass[all.size()]);
}
+ /**
+ * @param from class to check for inheritors
+ * @return inheritors of class
+ */
+ @NotNull
+ static Collection<PyClass> getInheritors(@NotNull final PyClass from) {
+ return PyClassInheritorsSearch.search(from, false).findAll();
+ }
+
public String getProcessedElementsHeader() {
return HEADER;
diff --git a/python/src/com/jetbrains/python/refactoring/classes/ui/PyMemberSelectionPanel.java b/python/src/com/jetbrains/python/refactoring/classes/ui/PyMemberSelectionPanel.java
index 6b380b4..0b6ef07 100644
--- a/python/src/com/jetbrains/python/refactoring/classes/ui/PyMemberSelectionPanel.java
+++ b/python/src/com/jetbrains/python/refactoring/classes/ui/PyMemberSelectionPanel.java
@@ -104,6 +104,6 @@
* Redraws table. Call it when some new data is available.
*/
public void redraw() {
- myTable.fireExternalDataChange();
+ myTable.redraw();
}
}
diff --git a/python/src/com/jetbrains/python/remote/PyRemoteSdkData.java b/python/src/com/jetbrains/python/remote/PyRemoteSdkAdditionalDataBase.java
similarity index 71%
copy from python/src/com/jetbrains/python/remote/PyRemoteSdkData.java
copy to python/src/com/jetbrains/python/remote/PyRemoteSdkAdditionalDataBase.java
index ea2f8df..deb8030 100644
--- a/python/src/com/jetbrains/python/remote/PyRemoteSdkData.java
+++ b/python/src/com/jetbrains/python/remote/PyRemoteSdkAdditionalDataBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,11 +15,10 @@
*/
package com.jetbrains.python.remote;
-import com.intellij.remotesdk.RemoteSdkData;
+import com.intellij.remotesdk2.RemoteSdkAdditionalData2;
/**
- * @author yole
+ * @author traff
*/
-public interface PyRemoteSdkData extends RemoteSdkData {
- String getSkeletonsPath();
+public interface PyRemoteSdkAdditionalDataBase extends RemoteSdkAdditionalData2<PyRemoteSdkCredentials>, PySkeletonsPathAware {
}
diff --git a/python/src/com/jetbrains/python/remote/PyRemoteSdkData.java b/python/src/com/jetbrains/python/remote/PyRemoteSdkCredentials.java
similarity index 81%
rename from python/src/com/jetbrains/python/remote/PyRemoteSdkData.java
rename to python/src/com/jetbrains/python/remote/PyRemoteSdkCredentials.java
index ea2f8df..5b5fc9b 100644
--- a/python/src/com/jetbrains/python/remote/PyRemoteSdkData.java
+++ b/python/src/com/jetbrains/python/remote/PyRemoteSdkCredentials.java
@@ -15,11 +15,11 @@
*/
package com.jetbrains.python.remote;
-import com.intellij.remotesdk.RemoteSdkData;
+import com.intellij.remotesdk.RemoteSdkCredentials;
/**
* @author yole
*/
-public interface PyRemoteSdkData extends RemoteSdkData {
- String getSkeletonsPath();
+public interface PyRemoteSdkCredentials extends RemoteSdkCredentials, PySkeletonsPathAware {
+
}
diff --git a/python/src/com/jetbrains/python/remote/PySkeletonsPathAware.java b/python/src/com/jetbrains/python/remote/PySkeletonsPathAware.java
new file mode 100644
index 0000000..789d1ba
--- /dev/null
+++ b/python/src/com/jetbrains/python/remote/PySkeletonsPathAware.java
@@ -0,0 +1,10 @@
+package com.jetbrains.python.remote;
+
+/**
+ * @author traff
+ */
+public interface PySkeletonsPathAware {
+ String getSkeletonsPath();
+
+ void setSkeletonsPath(String path);
+}
diff --git a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java
index 8be1df8..40e34f1 100644
--- a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java
+++ b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java
@@ -28,7 +28,7 @@
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.remotesdk.RemoteInterpreterException;
-import com.intellij.remotesdk.RemoteSdkData;
+import com.intellij.remotesdk.RemoteSdkCredentials;
import com.intellij.remotesdk.RemoteSshProcess;
import com.intellij.util.NullableConsumer;
import com.intellij.util.PathMappingSettings;
@@ -52,14 +52,14 @@
"Remote interpreter can't be executed. Please enable the Remote Hosts Access plugin.";
public abstract ProcessHandler startRemoteProcess(@Nullable Project project,
- @NotNull PyRemoteSdkData data,
+ @NotNull PyRemoteSdkCredentials data,
@NotNull GeneralCommandLine commandLine,
@Nullable
PathMappingSettings mappingSettings)
throws RemoteInterpreterException;
public abstract ProcessHandler startRemoteProcessWithPid(@Nullable Project project,
- @NotNull PyRemoteSdkData data,
+ @NotNull PyRemoteSdkCredentials data,
@NotNull GeneralCommandLine commandLine,
@Nullable
PathMappingSettings mappingSettings)
@@ -70,7 +70,7 @@
public abstract ProcessOutput runRemoteProcess(@Nullable Project project,
- RemoteSdkData data,
+ RemoteSdkCredentials data,
String[] command,
@Nullable String workingDir,
boolean askForSudo)
@@ -78,7 +78,7 @@
@NotNull
public abstract RemoteSshProcess createRemoteProcess(@Nullable Project project,
- @NotNull RemoteSdkData data,
+ @NotNull RemoteSdkCredentials data,
@NotNull GeneralCommandLine commandLine, boolean allocatePty)
throws RemoteInterpreterException;
@@ -89,18 +89,18 @@
@NotNull Sdk sdk,
String path);
- public abstract boolean ensureCanWrite(@Nullable Object projectOrComponent, RemoteSdkData data, String path);
+ public abstract boolean ensureCanWrite(@Nullable Object projectOrComponent, RemoteSdkCredentials data, String path);
@Nullable
- public abstract RemoteProjectSettings showRemoteProjectSettingsDialog(VirtualFile baseDir, RemoteSdkData data);
+ public abstract RemoteProjectSettings showRemoteProjectSettingsDialog(VirtualFile baseDir, RemoteSdkCredentials data);
public abstract void createDeployment(Project project,
VirtualFile projectDir,
RemoteProjectSettings settings,
- RemoteSdkData data);
+ RemoteSdkCredentials data);
public abstract void copyFromRemote(@NotNull Project project,
- RemoteSdkData data,
+ RemoteSdkCredentials data,
List<PathMappingSettings.PathMapping> mappings);
@Nullable
@@ -127,7 +127,7 @@
return FileUtil.toSystemIndependentName(path).replace('/', separator);
}
- public static void addHelpersMapping(@NotNull RemoteSdkData data, @Nullable PathMappingSettings newMappingSettings) {
+ public static void addHelpersMapping(@NotNull RemoteSdkCredentials data, @Nullable PathMappingSettings newMappingSettings) {
if (newMappingSettings == null) {
newMappingSettings = new PathMappingSettings();
}
@@ -135,7 +135,7 @@
}
public abstract PathMappingSettings setupMappings(@Nullable Project project,
- @NotNull PyRemoteSdkData data,
+ @NotNull PyRemoteSdkCredentials data,
@Nullable PathMappingSettings mappingSettings);
public abstract SdkAdditionalData loadRemoteSdkData(Sdk sdk, Element additional);
diff --git a/python/src/com/jetbrains/python/run/PyRemoteProcessStarter.java b/python/src/com/jetbrains/python/run/PyRemoteProcessStarter.java
index ba272c6..5941d5f 100644
--- a/python/src/com/jetbrains/python/run/PyRemoteProcessStarter.java
+++ b/python/src/com/jetbrains/python/run/PyRemoteProcessStarter.java
@@ -23,8 +23,11 @@
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SdkAdditionalData;
+import com.intellij.remotesdk2.RemoteSdkAdditionalData2;
import com.intellij.util.PathMappingSettings;
-import com.jetbrains.python.remote.PyRemoteSdkData;
+import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
+import com.jetbrains.python.remote.PyRemoteSdkCredentials;
import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -67,7 +70,14 @@
@Nullable PathMappingSettings settings)
throws ExecutionException {
- return manager.startRemoteProcess(project, (PyRemoteSdkData)sdk.getSdkAdditionalData(), commandLine,
- settings);
+ SdkAdditionalData data = sdk.getSdkAdditionalData();
+ assert data instanceof PyRemoteSdkAdditionalDataBase;
+ try {
+ return manager.startRemoteProcess(project, ((PyRemoteSdkAdditionalDataBase)data).getRemoteSdkCredentials(), commandLine,
+ settings);
+ }
+ catch (InterruptedException e) {
+ throw new ExecutionException(e); //TODO: handle exception
+ }
}
}
diff --git a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java
index 165d737..1043866 100644
--- a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java
+++ b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java
@@ -35,7 +35,7 @@
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.LocationNameFieldsBinding;
-import com.intellij.remotesdk.RemoteSdkDataHolder;
+import com.intellij.remotesdk.RemoteSdkCredentialsHolder;
import com.intellij.ui.CollectionComboBoxModel;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.components.JBCheckBox;
@@ -119,7 +119,7 @@
Iterables.removeIf(allSdks, new Predicate<Sdk>() {
@Override
public boolean apply(Sdk s) {
- return PythonSdkType.isInvalid(s) || PythonSdkType.isVirtualEnv(s) || RemoteSdkDataHolder.isRemoteSdk(s.getHomePath());
+ return PythonSdkType.isInvalid(s) || PythonSdkType.isVirtualEnv(s) || RemoteSdkCredentialsHolder.isRemoteSdk(s.getHomePath());
}
});
List<Sdk> sortedSdks = new ArrayList<Sdk>(allSdks);
diff --git a/python/src/com/jetbrains/python/sdk/PySdkUtil.java b/python/src/com/jetbrains/python/sdk/PySdkUtil.java
index a0ec72e..4185da7 100644
--- a/python/src/com/jetbrains/python/sdk/PySdkUtil.java
+++ b/python/src/com/jetbrains/python/sdk/PySdkUtil.java
@@ -26,6 +26,7 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.remotesdk.RemoteCredentials;
+import com.intellij.remotesdk2.RemoteSdkAdditionalData2;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
@@ -213,7 +214,7 @@
}
public static boolean isRemote(@Nullable Sdk sdk) {
- return sdk != null && sdk.getSdkAdditionalData() instanceof RemoteCredentials;
+ return sdk != null && sdk.getSdkAdditionalData() instanceof RemoteSdkAdditionalData2;
}
public static boolean isElementInSkeletons(@NotNull final PsiElement element) {
diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java
index 8e3f18a..df04801 100644
--- a/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java
+++ b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java
@@ -28,12 +28,12 @@
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.*;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
-import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.NullableConsumer;
import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import org.jetbrains.annotations.Nullable;
+import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
@@ -53,13 +53,14 @@
public static void show(final Project project,
final Sdk[] existingSdks,
- DialogWrapper component, final RelativePoint popupPoint,
+ DialogWrapper moreDialog,
+ JComponent ownerComponent, final Point popupPoint,
final boolean showMore,
final NullableConsumer<Sdk> callback) {
- myMore = component;
- final ListPopupStep sdkHomesStep = new PythonSdkDetailsStep(project, popupPoint.getComponent(), existingSdks, showMore, callback);
+ myMore = moreDialog;
+ final ListPopupStep sdkHomesStep = new PythonSdkDetailsStep(project, ownerComponent, existingSdks, showMore, callback);
final ListPopup popup = JBPopupFactory.getInstance().createListPopup(sdkHomesStep);
- popup.show(popupPoint);
+ popup.showInScreenCoordinates(ownerComponent, popupPoint);
}
public PythonSdkDetailsStep(Project project,
diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java
index 3ad05e0..6aa0c6d 100644
--- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java
+++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java
@@ -51,9 +51,8 @@
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.reference.SoftReference;
-import com.intellij.remotesdk.RemoteSdkData;
-import com.intellij.remotesdk.RemoteSdkDataHolder;
-import com.intellij.ui.awt.RelativePoint;
+import com.intellij.remotesdk.RemoteSdkCredentials;
+import com.intellij.remotesdk.RemoteSdkCredentialsHolder;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Consumer;
import com.intellij.util.NullableConsumer;
@@ -280,8 +279,10 @@
public void showCustomCreateUI(SdkModel sdkModel, final JComponent parentComponent, final Consumer<Sdk> sdkCreatedCallback) {
Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(parentComponent));
+ final Point point = parentComponent.getMousePosition();
+ SwingUtilities.convertPointToScreen(point, parentComponent);
PythonSdkDetailsStep
- .show(project, sdkModel.getSdks(), null, RelativePoint.getCenterOf(parentComponent), true, new NullableConsumer<Sdk>() {
+ .show(project, sdkModel.getSdks(), null, parentComponent, point, false, new NullableConsumer<Sdk>() {
@Override
public void consume(@Nullable Sdk sdk) {
if (sdk != null) {
@@ -436,7 +437,7 @@
@Override
public SdkAdditionalData loadAdditionalData(@NotNull final Sdk currentSdk, final Element additional) {
- if (RemoteSdkDataHolder.isRemoteSdk(currentSdk.getHomePath())) {
+ if (RemoteSdkCredentialsHolder.isRemoteSdk(currentSdk.getHomePath())) {
PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
if (manager != null) {
return manager.loadRemoteSdkData(currentSdk, additional);
@@ -937,9 +938,9 @@
}
public static boolean isIncompleteRemote(Sdk sdk) {
- if (sdk.getSdkAdditionalData() instanceof RemoteSdkData) {
+ if (sdk.getSdkAdditionalData() instanceof RemoteSdkCredentials) {
//noinspection ConstantConditions
- if (!((RemoteSdkData)sdk.getSdkAdditionalData()).isInitialized()) {
+ if (!((RemoteSdkCredentials)sdk.getSdkAdditionalData()).isInitialized()) {
return true;
}
}
diff --git a/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
index 2c45c83..9de862f 100644
--- a/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
+++ b/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
@@ -20,6 +20,7 @@
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
+import com.jetbrains.python.PythonHelpersLocator;
import java.io.File;
import java.util.Collection;
@@ -39,6 +40,7 @@
public Collection<String> suggestHomePaths() {
Set<String> candidates = new TreeSet<String>();
findInCandidatePaths(candidates, "python.exe", "jython.bat", "pypy.exe");
+ candidates.add(PythonHelpersLocator.getHelpersRoot().getParent());
return candidates;
}
@@ -75,7 +77,7 @@
if (rootVDir instanceof NewVirtualFile) {
((NewVirtualFile)rootVDir).markDirty();
}
- rootVDir.refresh(false, false);
+ rootVDir.refresh(true, false);
for (VirtualFile dir : rootVDir.getChildren()) {
if (dir.isDirectory() && dir.getName().toLowerCase().startsWith(dir_prefix)) {
VirtualFile python_exe = dir.findChild(exe_name);
diff --git a/python/src/com/jetbrains/python/structureView/PyInheritedMembersFilter.java b/python/src/com/jetbrains/python/structureView/PyInheritedMembersFilter.java
index b61edd6..2b5483f 100644
--- a/python/src/com/jetbrains/python/structureView/PyInheritedMembersFilter.java
+++ b/python/src/com/jetbrains/python/structureView/PyInheritedMembersFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -64,11 +64,13 @@
AllIcons.Hierarchy.Supertypes);
}
+ @NotNull
@Override
public String getCheckBoxText() {
return IdeBundle.message("file.structure.toggle.show.inherited");
}
+ @NotNull
@Override
public Shortcut[] getShortcut() {
return KeymapManager.getInstance().getActiveKeymap().getShortcuts("FileStructurePopup");
diff --git a/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java b/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java
index fd043ce..93c44f7 100644
--- a/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java
+++ b/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.*;
import icons.PythonIcons;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -120,6 +121,7 @@
return name != null ? name.hashCode() : 0;
}
+ @NotNull
public StructureViewTreeElement[] getChildren() {
final Collection<StructureViewTreeElement> children = new ArrayList<StructureViewTreeElement>();
for (PyElement e : getElementChildren(myElement)) {
@@ -232,6 +234,7 @@
return false;
}
+ @NotNull
@Override
public ItemPresentation getPresentation() {
return new ColoredItemPresentation() {
diff --git a/python/src/com/jetbrains/python/structureView/PyStructureViewModel.java b/python/src/com/jetbrains/python/structureView/PyStructureViewModel.java
index 6621792..3e8e4f1 100644
--- a/python/src/com/jetbrains/python/structureView/PyStructureViewModel.java
+++ b/python/src/com/jetbrains/python/structureView/PyStructureViewModel.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,7 +66,7 @@
}
@Override
- public boolean isAutoExpand(StructureViewTreeElement element) {
+ public boolean isAutoExpand(@NotNull StructureViewTreeElement element) {
return element.getValue() instanceof PsiFile;
}
diff --git a/python/src/icons/PythonIcons.java b/python/src/icons/PythonIcons.java
index a65d468..2adb29d 100644
--- a/python/src/icons/PythonIcons.java
+++ b/python/src/icons/PythonIcons.java
@@ -50,6 +50,7 @@
public static final Icon PythonClosed = load("/icons/com/jetbrains/python/pythonClosed.png"); // 16x16
public static final Icon PythonTests = load("/icons/com/jetbrains/python/pythonTests.png"); // 16x16
public static final Icon Skeleton = load("/icons/com/jetbrains/python/skeleton.png"); // 16x16
+ public static final Icon TemplateRoot = load("/icons/com/jetbrains/python/templateRoot.png"); // 16x16
public static final Icon Virtualenv = load("/icons/com/jetbrains/python/virtualenv.png"); // 16x16
}